“What is the maximum that Player 1 can win?”How can I optimize this code that finds the GCD?What is the 10001st prime number?Playing “craps” for the winWhat does the Bob say?Find the number of possible infinite cycles that Bessie the Cow can get stuck inFinding the maximum GCD of all pairsCompute the number of ways a given amount (cents) can be changedGiven a binary tree, find the maximum path sumFind the maximum possible summation of differences of consecutive elements“What is the fastest solution for finding the maximum sum of a subarray?”

Putting out of focus command for LaTeX/fuzzying the resulting pdf

Why aren't (poly-)cotton tents more popular?

Fitting a mixture of two normal distributions for a data set?

Is it OK to bottle condition using previously contaminated bottles?

Why cruise at 7000' in an A319?

What do you call the action of someone tackling a stronger person?

What is this opening trap called, and how should I play afterwards? How can I refute the gambit, and play if I accept it?

Why does the A-4 Skyhawk sit nose-up when on ground?

Why does the numerical solution of an ODE move away from an unstable equilibrium?

How could mana leakage be dangerous to a elf?

Why isn’t the tax system continuous rather than bracketed?

Singing along to guitar chords (harmony)

Do equal angles necessarily mean a polygon is regular?

Was touching your nose a greeting in second millenium Mesopotamia?

How to append a matrix element by element?

How well known and how commonly used was Huffman coding in 1979?

Does squid ink pasta bleed?

How can I convince my reader that I will not use a certain trope?

How risky is real estate?

What would Earth look like at night in medieval times?

Inverse-quotes-quine

Is adding a new player (or players) a DM decision, or a group decision?

MH370 blackbox - is it still possible to retrieve data from it?

Links to webpages in books



“What is the maximum that Player 1 can win?”


How can I optimize this code that finds the GCD?What is the 10001st prime number?Playing “craps” for the winWhat does the Bob say?Find the number of possible infinite cycles that Bessie the Cow can get stuck inFinding the maximum GCD of all pairsCompute the number of ways a given amount (cents) can be changedGiven a binary tree, find the maximum path sumFind the maximum possible summation of differences of consecutive elements“What is the fastest solution for finding the maximum sum of a subarray?”






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








6












$begingroup$


This is a question that I encountered in one of the competitive coding tests. The question goes as follows:




A 2-player game is being played. There is a single pile of stones. Every stone has an amount (positive) written on top of it. At every turn, a player can take the top 1 or 2 or 3 stones and add to his kitty. Both players want to maximize their winnings. Assuming both players play the game optimally and Player 1 starts the game, what is the maximum amount that Player 1 can win?




I have devised the following recursive approach:



class Main 
public static void main(String[] args)
int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
int sum = 0;
for (int i=0;i<a.length; i++)
sum += a[i];

System.out.println(maxPlayer1(a, 0, sum, 0, a.length));

public static int maxPlayer1(int[] a, int currSum, int sum, int start, int len)
if (len-start <=3)
int val = 0;
for (int i=start; i<len; i++)
val += a[i];

return val;


int v1 = a[start] + (sum - currSum - a[start]) -
maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);

return Math.max(v1, Math.max(v2, v3));




I have checked my solution on a few inputs. Is my algorithm correct?










share|improve this question











$endgroup$







  • 5




    $begingroup$
    A few inputs? Nope. You need a lot of inputs. One thing to do is to test your solution against more inputs. This way, you won't need to ask whether your algorithm is correct or not; you know your algorithm is right. Therefore, test some more inputs, so that you know your algorithm works correctly.
    $endgroup$
    – Justin
    Jun 16 at 16:25






  • 8




    $begingroup$
    There is nothing wrong with posting the unit tests you already implemented as an appendix in your question. This makes our task helping you easier. When asking whether your algorithm is correct, this rings bells here. I suggest to read the policy: codereview.stackexchange.com/help/on-topic
    $endgroup$
    – dfhwze
    Jun 16 at 16:34






  • 2




    $begingroup$
    A "pile of stones" together with "written on top" sounds a lot like the players would only be able to look at the top stone, with the scores of all other stones being a secret until the top stone is removed. This should be clarified before the algorithm can be analyzed.
    $endgroup$
    – Roland Illig
    Jun 16 at 22:53






  • 2




    $begingroup$
    @RolandIllig There are very few scenarios where you gain by not taking all 3 stones - I don't think that can be the intention. I can see just the few options where you know you will end up with the same number of stones and tactically not take one with low number in hope you can get a higher one instead… but this is subject to luck. So, strategy would be fairly simple - take the maximum number of stones, except don't take stones with 1 in case you still end up with the same number of stones in the end. (anything else depends on luck).
    $endgroup$
    – Zizy Archer
    Jun 17 at 8:58






  • 2




    $begingroup$
    Why do you need to pass a.length as a separate argument?
    $endgroup$
    – Federico Poloni
    Jun 17 at 10:05

















6












$begingroup$


This is a question that I encountered in one of the competitive coding tests. The question goes as follows:




A 2-player game is being played. There is a single pile of stones. Every stone has an amount (positive) written on top of it. At every turn, a player can take the top 1 or 2 or 3 stones and add to his kitty. Both players want to maximize their winnings. Assuming both players play the game optimally and Player 1 starts the game, what is the maximum amount that Player 1 can win?




I have devised the following recursive approach:



class Main 
public static void main(String[] args)
int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
int sum = 0;
for (int i=0;i<a.length; i++)
sum += a[i];

System.out.println(maxPlayer1(a, 0, sum, 0, a.length));

public static int maxPlayer1(int[] a, int currSum, int sum, int start, int len)
if (len-start <=3)
int val = 0;
for (int i=start; i<len; i++)
val += a[i];

return val;


int v1 = a[start] + (sum - currSum - a[start]) -
maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);

return Math.max(v1, Math.max(v2, v3));




I have checked my solution on a few inputs. Is my algorithm correct?










share|improve this question











$endgroup$







  • 5




    $begingroup$
    A few inputs? Nope. You need a lot of inputs. One thing to do is to test your solution against more inputs. This way, you won't need to ask whether your algorithm is correct or not; you know your algorithm is right. Therefore, test some more inputs, so that you know your algorithm works correctly.
    $endgroup$
    – Justin
    Jun 16 at 16:25






  • 8




    $begingroup$
    There is nothing wrong with posting the unit tests you already implemented as an appendix in your question. This makes our task helping you easier. When asking whether your algorithm is correct, this rings bells here. I suggest to read the policy: codereview.stackexchange.com/help/on-topic
    $endgroup$
    – dfhwze
    Jun 16 at 16:34






  • 2




    $begingroup$
    A "pile of stones" together with "written on top" sounds a lot like the players would only be able to look at the top stone, with the scores of all other stones being a secret until the top stone is removed. This should be clarified before the algorithm can be analyzed.
    $endgroup$
    – Roland Illig
    Jun 16 at 22:53






  • 2




    $begingroup$
    @RolandIllig There are very few scenarios where you gain by not taking all 3 stones - I don't think that can be the intention. I can see just the few options where you know you will end up with the same number of stones and tactically not take one with low number in hope you can get a higher one instead… but this is subject to luck. So, strategy would be fairly simple - take the maximum number of stones, except don't take stones with 1 in case you still end up with the same number of stones in the end. (anything else depends on luck).
    $endgroup$
    – Zizy Archer
    Jun 17 at 8:58






  • 2




    $begingroup$
    Why do you need to pass a.length as a separate argument?
    $endgroup$
    – Federico Poloni
    Jun 17 at 10:05













6












6








6


2



$begingroup$


This is a question that I encountered in one of the competitive coding tests. The question goes as follows:




A 2-player game is being played. There is a single pile of stones. Every stone has an amount (positive) written on top of it. At every turn, a player can take the top 1 or 2 or 3 stones and add to his kitty. Both players want to maximize their winnings. Assuming both players play the game optimally and Player 1 starts the game, what is the maximum amount that Player 1 can win?




I have devised the following recursive approach:



class Main 
public static void main(String[] args)
int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
int sum = 0;
for (int i=0;i<a.length; i++)
sum += a[i];

System.out.println(maxPlayer1(a, 0, sum, 0, a.length));

public static int maxPlayer1(int[] a, int currSum, int sum, int start, int len)
if (len-start <=3)
int val = 0;
for (int i=start; i<len; i++)
val += a[i];

return val;


int v1 = a[start] + (sum - currSum - a[start]) -
maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);

return Math.max(v1, Math.max(v2, v3));




I have checked my solution on a few inputs. Is my algorithm correct?










share|improve this question











$endgroup$




This is a question that I encountered in one of the competitive coding tests. The question goes as follows:




A 2-player game is being played. There is a single pile of stones. Every stone has an amount (positive) written on top of it. At every turn, a player can take the top 1 or 2 or 3 stones and add to his kitty. Both players want to maximize their winnings. Assuming both players play the game optimally and Player 1 starts the game, what is the maximum amount that Player 1 can win?




I have devised the following recursive approach:



class Main 
public static void main(String[] args)
int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
int sum = 0;
for (int i=0;i<a.length; i++)
sum += a[i];

System.out.println(maxPlayer1(a, 0, sum, 0, a.length));

public static int maxPlayer1(int[] a, int currSum, int sum, int start, int len)
if (len-start <=3)
int val = 0;
for (int i=start; i<len; i++)
val += a[i];

return val;


int v1 = a[start] + (sum - currSum - a[start]) -
maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);

return Math.max(v1, Math.max(v2, v3));




I have checked my solution on a few inputs. Is my algorithm correct?







java algorithm programming-challenge recursion






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jun 17 at 4:54









Jamal

31.2k12 gold badges123 silver badges230 bronze badges




31.2k12 gold badges123 silver badges230 bronze badges










asked Jun 16 at 15:54









User_TargaryenUser_Targaryen

1731 silver badge5 bronze badges




1731 silver badge5 bronze badges







  • 5




    $begingroup$
    A few inputs? Nope. You need a lot of inputs. One thing to do is to test your solution against more inputs. This way, you won't need to ask whether your algorithm is correct or not; you know your algorithm is right. Therefore, test some more inputs, so that you know your algorithm works correctly.
    $endgroup$
    – Justin
    Jun 16 at 16:25






  • 8




    $begingroup$
    There is nothing wrong with posting the unit tests you already implemented as an appendix in your question. This makes our task helping you easier. When asking whether your algorithm is correct, this rings bells here. I suggest to read the policy: codereview.stackexchange.com/help/on-topic
    $endgroup$
    – dfhwze
    Jun 16 at 16:34






  • 2




    $begingroup$
    A "pile of stones" together with "written on top" sounds a lot like the players would only be able to look at the top stone, with the scores of all other stones being a secret until the top stone is removed. This should be clarified before the algorithm can be analyzed.
    $endgroup$
    – Roland Illig
    Jun 16 at 22:53






  • 2




    $begingroup$
    @RolandIllig There are very few scenarios where you gain by not taking all 3 stones - I don't think that can be the intention. I can see just the few options where you know you will end up with the same number of stones and tactically not take one with low number in hope you can get a higher one instead… but this is subject to luck. So, strategy would be fairly simple - take the maximum number of stones, except don't take stones with 1 in case you still end up with the same number of stones in the end. (anything else depends on luck).
    $endgroup$
    – Zizy Archer
    Jun 17 at 8:58






  • 2




    $begingroup$
    Why do you need to pass a.length as a separate argument?
    $endgroup$
    – Federico Poloni
    Jun 17 at 10:05












  • 5




    $begingroup$
    A few inputs? Nope. You need a lot of inputs. One thing to do is to test your solution against more inputs. This way, you won't need to ask whether your algorithm is correct or not; you know your algorithm is right. Therefore, test some more inputs, so that you know your algorithm works correctly.
    $endgroup$
    – Justin
    Jun 16 at 16:25






  • 8




    $begingroup$
    There is nothing wrong with posting the unit tests you already implemented as an appendix in your question. This makes our task helping you easier. When asking whether your algorithm is correct, this rings bells here. I suggest to read the policy: codereview.stackexchange.com/help/on-topic
    $endgroup$
    – dfhwze
    Jun 16 at 16:34






  • 2




    $begingroup$
    A "pile of stones" together with "written on top" sounds a lot like the players would only be able to look at the top stone, with the scores of all other stones being a secret until the top stone is removed. This should be clarified before the algorithm can be analyzed.
    $endgroup$
    – Roland Illig
    Jun 16 at 22:53






  • 2




    $begingroup$
    @RolandIllig There are very few scenarios where you gain by not taking all 3 stones - I don't think that can be the intention. I can see just the few options where you know you will end up with the same number of stones and tactically not take one with low number in hope you can get a higher one instead… but this is subject to luck. So, strategy would be fairly simple - take the maximum number of stones, except don't take stones with 1 in case you still end up with the same number of stones in the end. (anything else depends on luck).
    $endgroup$
    – Zizy Archer
    Jun 17 at 8:58






  • 2




    $begingroup$
    Why do you need to pass a.length as a separate argument?
    $endgroup$
    – Federico Poloni
    Jun 17 at 10:05







5




5




$begingroup$
A few inputs? Nope. You need a lot of inputs. One thing to do is to test your solution against more inputs. This way, you won't need to ask whether your algorithm is correct or not; you know your algorithm is right. Therefore, test some more inputs, so that you know your algorithm works correctly.
$endgroup$
– Justin
Jun 16 at 16:25




$begingroup$
A few inputs? Nope. You need a lot of inputs. One thing to do is to test your solution against more inputs. This way, you won't need to ask whether your algorithm is correct or not; you know your algorithm is right. Therefore, test some more inputs, so that you know your algorithm works correctly.
$endgroup$
– Justin
Jun 16 at 16:25




8




8




$begingroup$
There is nothing wrong with posting the unit tests you already implemented as an appendix in your question. This makes our task helping you easier. When asking whether your algorithm is correct, this rings bells here. I suggest to read the policy: codereview.stackexchange.com/help/on-topic
$endgroup$
– dfhwze
Jun 16 at 16:34




$begingroup$
There is nothing wrong with posting the unit tests you already implemented as an appendix in your question. This makes our task helping you easier. When asking whether your algorithm is correct, this rings bells here. I suggest to read the policy: codereview.stackexchange.com/help/on-topic
$endgroup$
– dfhwze
Jun 16 at 16:34




2




2




$begingroup$
A "pile of stones" together with "written on top" sounds a lot like the players would only be able to look at the top stone, with the scores of all other stones being a secret until the top stone is removed. This should be clarified before the algorithm can be analyzed.
$endgroup$
– Roland Illig
Jun 16 at 22:53




$begingroup$
A "pile of stones" together with "written on top" sounds a lot like the players would only be able to look at the top stone, with the scores of all other stones being a secret until the top stone is removed. This should be clarified before the algorithm can be analyzed.
$endgroup$
– Roland Illig
Jun 16 at 22:53




2




2




$begingroup$
@RolandIllig There are very few scenarios where you gain by not taking all 3 stones - I don't think that can be the intention. I can see just the few options where you know you will end up with the same number of stones and tactically not take one with low number in hope you can get a higher one instead… but this is subject to luck. So, strategy would be fairly simple - take the maximum number of stones, except don't take stones with 1 in case you still end up with the same number of stones in the end. (anything else depends on luck).
$endgroup$
– Zizy Archer
Jun 17 at 8:58




$begingroup$
@RolandIllig There are very few scenarios where you gain by not taking all 3 stones - I don't think that can be the intention. I can see just the few options where you know you will end up with the same number of stones and tactically not take one with low number in hope you can get a higher one instead… but this is subject to luck. So, strategy would be fairly simple - take the maximum number of stones, except don't take stones with 1 in case you still end up with the same number of stones in the end. (anything else depends on luck).
$endgroup$
– Zizy Archer
Jun 17 at 8:58




2




2




$begingroup$
Why do you need to pass a.length as a separate argument?
$endgroup$
– Federico Poloni
Jun 17 at 10:05




$begingroup$
Why do you need to pass a.length as a separate argument?
$endgroup$
– Federico Poloni
Jun 17 at 10:05










4 Answers
4






active

oldest

votes


















17












$begingroup$

Usability



I have a remark about defining recursive functions.
You don't want consumers of your API to think about the intermediate variables and their initial value. The consumer does not care you are using recursion internally.



Make your recursive function private.



private static int maxPlayer1(int[] a, int currSum, int sum, int start, int len) 


And create a public API entrypoint.



public static int maxPlayer1(int[] a) 
final int sum = IntStream.of(a).sum();
return maxPlayer1(a, 0, sum, 0, a.length);



The consumer can now call your API without getting a headache:



public static void main(String[] args) 
final int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
System.out.println(maxPlayer1(a));



As compared to the original code the consumer had to write.




public static void main(String[] args) 
int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
int sum = 0;
for (int i=0;i<a.length; i++)
sum += a[i];

System.out.println(maxPlayer1(a, 0, sum, 0, a.length));







share|improve this answer











$endgroup$




















    7












    $begingroup$

    A note on efficiency. Currently the code exhibit an exponential time complexity. It can be reduced significantly.



    Notice that the same position is inspected more than once. For example, the opening sequences 3, 1, 2, 2 and 1, 3 all lead to the same position. Further down the game the situation aggravates.



    Keep track of the positions already inspected, and before diving into the recursion check whether it is still unknown. Since the position is just an integer (an amount of stones remaining), the cost of tracking is $O(n)$ space.



    Further improvement is of course alpha-beta pruning.






    share|improve this answer









    $endgroup$




















      7












      $begingroup$

      The natural way to tackle this problem (as in many similar games) is starting from the final position.



      Let B[k] be the maximum score that Player 1 can get if the game starts with only the last k stones left. B[1], B[2], B[3] are initial values that can be computed directly (just take all remaining stones), and then you can fill in B[4], B[5], B[6], ... in this order, since B[k] only depends on B[k-1], B[k-2], B[k-3]; so you can write your code as a loop for k=4,5,6,..., a.length. The resulting algorithm is linear, without no recursion, branching, or approximations required.



      Instead, it looks like you are trying to compute the entries B[i] starting from B[a.length]. This leads to a more complicated structure where you make recursive calls, and re-compute the same values B[i] multiple times, as pointed out also by @vnp's answer.



      Once you have figured out how to fill the B array in this way, a further improvement is realizing that you only need to keep the last three values B[k], B[k-1], B[k-2] at each step (and possibly also the partial sum a[k-2] + ... + a[a.length]). This gives a solution in O(1) space.



      If you want to compare with another famous function in which f(n) depends on its previous values, what you wrote is like computing Fibonacci numbers recursively via return fibonacci(n-1) + fibonacci(n-2). What I suggest above is computing iteratively f[0], f[1], f[2], ... starting from f[0].






      share|improve this answer










      New contributor



      Federico Poloni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      $endgroup$












      • $begingroup$
        fantastic answer and explanation. +1
        $endgroup$
        – Khan Power
        Jun 17 at 16:47


















      3












      $begingroup$

      I am not too happy about the variable name currSum, it is hard to see the meaning of this variable from the name alone.



      Consider takenValue or something similar as a variable name.



      Note that



      a[start] + (sum - currSum - a[start])



      Simplifies to



      sum - currSum



      And similarily for the other cases so;



       int v1 = a[start] + (sum - currSum - a[start]) - 
      maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

      int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
      maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

      int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
      maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


      simplifies to



       int v1 = sum - currSum - 
      maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

      int v2 = sum - currSum -
      maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

      int v3 = sum - currSum -
      maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


      We should also try to capture the meaning of a[start]+...a[start+n], we can do this by introducing a new variable takenInCurrentStep



      Also



       int val = 0;
      for (int i=start; i<len; i++)
      val += a[i];

      return val;


      Is needlessly complicated. We can write this as :



       return sum-currSum;


      Bringing this all together :



       public static int maxPlayer1(int[] a, int takenValue, int sum, int start, int len) 
      if (len-start <=3)
      return sum-takenValue;


      int valueTakenInCurrentStep = 0;
      int lasttokensTakenInCurrentStep = start;
      int valueTakenInCurrentStep = a[lasttokensTakenInCurrentStep];

      int v1 = sum - takenValue -
      maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

      int lasttokensTakenInCurrentStep ++;
      int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];

      int v2 = sum - takenValue -
      maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

      int lasttokensTakenInCurrentStep ++;
      int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];
      int v3 = sum - takenValue -
      maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

      return Math.max(v1, Math.max(v2, v3));

      }


      The algorithm can be described as;



      We have a method that calculates the maximum that the current player can get from the remaining of the game. The method takes the value of all the tokens, the value of the tokens that are no longer available, the value of all tokens, the index of the first currently available token, and the total number of tokens.



      It works by if there are 3 or less tokens left return the value of the remaining tokens, which is equal to the value of all tokens minus the value of the tokens already taken.
      If there are more than 3 tokens return the maximum of the value of remaining tokens minus the amount that the other player gets if current player takes 1,2 or 3 tokens.



      This is a correct algorithm, and we can prove this by incursion.






      share|improve this answer









      $endgroup$















        Your Answer






        StackExchange.ifUsing("editor", function ()
        StackExchange.using("externalEditor", function ()
        StackExchange.using("snippets", function ()
        StackExchange.snippets.init();
        );
        );
        , "code-snippets");

        StackExchange.ready(function()
        var channelOptions =
        tags: "".split(" "),
        id: "196"
        ;
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function()
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled)
        StackExchange.using("snippets", function()
        createEditor();
        );

        else
        createEditor();

        );

        function createEditor()
        StackExchange.prepareEditor(
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: false,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        imageUploader:
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        ,
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );













        draft saved

        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f222413%2fwhat-is-the-maximum-that-player-1-can-win%23new-answer', 'question_page');

        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        17












        $begingroup$

        Usability



        I have a remark about defining recursive functions.
        You don't want consumers of your API to think about the intermediate variables and their initial value. The consumer does not care you are using recursion internally.



        Make your recursive function private.



        private static int maxPlayer1(int[] a, int currSum, int sum, int start, int len) 


        And create a public API entrypoint.



        public static int maxPlayer1(int[] a) 
        final int sum = IntStream.of(a).sum();
        return maxPlayer1(a, 0, sum, 0, a.length);



        The consumer can now call your API without getting a headache:



        public static void main(String[] args) 
        final int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
        System.out.println(maxPlayer1(a));



        As compared to the original code the consumer had to write.




        public static void main(String[] args) 
        int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
        int sum = 0;
        for (int i=0;i<a.length; i++)
        sum += a[i];

        System.out.println(maxPlayer1(a, 0, sum, 0, a.length));







        share|improve this answer











        $endgroup$

















          17












          $begingroup$

          Usability



          I have a remark about defining recursive functions.
          You don't want consumers of your API to think about the intermediate variables and their initial value. The consumer does not care you are using recursion internally.



          Make your recursive function private.



          private static int maxPlayer1(int[] a, int currSum, int sum, int start, int len) 


          And create a public API entrypoint.



          public static int maxPlayer1(int[] a) 
          final int sum = IntStream.of(a).sum();
          return maxPlayer1(a, 0, sum, 0, a.length);



          The consumer can now call your API without getting a headache:



          public static void main(String[] args) 
          final int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
          System.out.println(maxPlayer1(a));



          As compared to the original code the consumer had to write.




          public static void main(String[] args) 
          int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
          int sum = 0;
          for (int i=0;i<a.length; i++)
          sum += a[i];

          System.out.println(maxPlayer1(a, 0, sum, 0, a.length));







          share|improve this answer











          $endgroup$















            17












            17








            17





            $begingroup$

            Usability



            I have a remark about defining recursive functions.
            You don't want consumers of your API to think about the intermediate variables and their initial value. The consumer does not care you are using recursion internally.



            Make your recursive function private.



            private static int maxPlayer1(int[] a, int currSum, int sum, int start, int len) 


            And create a public API entrypoint.



            public static int maxPlayer1(int[] a) 
            final int sum = IntStream.of(a).sum();
            return maxPlayer1(a, 0, sum, 0, a.length);



            The consumer can now call your API without getting a headache:



            public static void main(String[] args) 
            final int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
            System.out.println(maxPlayer1(a));



            As compared to the original code the consumer had to write.




            public static void main(String[] args) 
            int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
            int sum = 0;
            for (int i=0;i<a.length; i++)
            sum += a[i];

            System.out.println(maxPlayer1(a, 0, sum, 0, a.length));







            share|improve this answer











            $endgroup$



            Usability



            I have a remark about defining recursive functions.
            You don't want consumers of your API to think about the intermediate variables and their initial value. The consumer does not care you are using recursion internally.



            Make your recursive function private.



            private static int maxPlayer1(int[] a, int currSum, int sum, int start, int len) 


            And create a public API entrypoint.



            public static int maxPlayer1(int[] a) 
            final int sum = IntStream.of(a).sum();
            return maxPlayer1(a, 0, sum, 0, a.length);



            The consumer can now call your API without getting a headache:



            public static void main(String[] args) 
            final int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
            System.out.println(maxPlayer1(a));



            As compared to the original code the consumer had to write.




            public static void main(String[] args) 
            int a[] = 1,2,3,7,4,8,1,8,1,9,10,2,5,2,3;
            int sum = 0;
            for (int i=0;i<a.length; i++)
            sum += a[i];

            System.out.println(maxPlayer1(a, 0, sum, 0, a.length));








            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jun 16 at 17:51

























            answered Jun 16 at 17:23









            dfhwzedfhwze

            3,3211 gold badge6 silver badges32 bronze badges




            3,3211 gold badge6 silver badges32 bronze badges























                7












                $begingroup$

                A note on efficiency. Currently the code exhibit an exponential time complexity. It can be reduced significantly.



                Notice that the same position is inspected more than once. For example, the opening sequences 3, 1, 2, 2 and 1, 3 all lead to the same position. Further down the game the situation aggravates.



                Keep track of the positions already inspected, and before diving into the recursion check whether it is still unknown. Since the position is just an integer (an amount of stones remaining), the cost of tracking is $O(n)$ space.



                Further improvement is of course alpha-beta pruning.






                share|improve this answer









                $endgroup$

















                  7












                  $begingroup$

                  A note on efficiency. Currently the code exhibit an exponential time complexity. It can be reduced significantly.



                  Notice that the same position is inspected more than once. For example, the opening sequences 3, 1, 2, 2 and 1, 3 all lead to the same position. Further down the game the situation aggravates.



                  Keep track of the positions already inspected, and before diving into the recursion check whether it is still unknown. Since the position is just an integer (an amount of stones remaining), the cost of tracking is $O(n)$ space.



                  Further improvement is of course alpha-beta pruning.






                  share|improve this answer









                  $endgroup$















                    7












                    7








                    7





                    $begingroup$

                    A note on efficiency. Currently the code exhibit an exponential time complexity. It can be reduced significantly.



                    Notice that the same position is inspected more than once. For example, the opening sequences 3, 1, 2, 2 and 1, 3 all lead to the same position. Further down the game the situation aggravates.



                    Keep track of the positions already inspected, and before diving into the recursion check whether it is still unknown. Since the position is just an integer (an amount of stones remaining), the cost of tracking is $O(n)$ space.



                    Further improvement is of course alpha-beta pruning.






                    share|improve this answer









                    $endgroup$



                    A note on efficiency. Currently the code exhibit an exponential time complexity. It can be reduced significantly.



                    Notice that the same position is inspected more than once. For example, the opening sequences 3, 1, 2, 2 and 1, 3 all lead to the same position. Further down the game the situation aggravates.



                    Keep track of the positions already inspected, and before diving into the recursion check whether it is still unknown. Since the position is just an integer (an amount of stones remaining), the cost of tracking is $O(n)$ space.



                    Further improvement is of course alpha-beta pruning.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jun 16 at 20:57









                    vnpvnp

                    41.8k2 gold badges35 silver badges107 bronze badges




                    41.8k2 gold badges35 silver badges107 bronze badges





















                        7












                        $begingroup$

                        The natural way to tackle this problem (as in many similar games) is starting from the final position.



                        Let B[k] be the maximum score that Player 1 can get if the game starts with only the last k stones left. B[1], B[2], B[3] are initial values that can be computed directly (just take all remaining stones), and then you can fill in B[4], B[5], B[6], ... in this order, since B[k] only depends on B[k-1], B[k-2], B[k-3]; so you can write your code as a loop for k=4,5,6,..., a.length. The resulting algorithm is linear, without no recursion, branching, or approximations required.



                        Instead, it looks like you are trying to compute the entries B[i] starting from B[a.length]. This leads to a more complicated structure where you make recursive calls, and re-compute the same values B[i] multiple times, as pointed out also by @vnp's answer.



                        Once you have figured out how to fill the B array in this way, a further improvement is realizing that you only need to keep the last three values B[k], B[k-1], B[k-2] at each step (and possibly also the partial sum a[k-2] + ... + a[a.length]). This gives a solution in O(1) space.



                        If you want to compare with another famous function in which f(n) depends on its previous values, what you wrote is like computing Fibonacci numbers recursively via return fibonacci(n-1) + fibonacci(n-2). What I suggest above is computing iteratively f[0], f[1], f[2], ... starting from f[0].






                        share|improve this answer










                        New contributor



                        Federico Poloni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.





                        $endgroup$












                        • $begingroup$
                          fantastic answer and explanation. +1
                          $endgroup$
                          – Khan Power
                          Jun 17 at 16:47















                        7












                        $begingroup$

                        The natural way to tackle this problem (as in many similar games) is starting from the final position.



                        Let B[k] be the maximum score that Player 1 can get if the game starts with only the last k stones left. B[1], B[2], B[3] are initial values that can be computed directly (just take all remaining stones), and then you can fill in B[4], B[5], B[6], ... in this order, since B[k] only depends on B[k-1], B[k-2], B[k-3]; so you can write your code as a loop for k=4,5,6,..., a.length. The resulting algorithm is linear, without no recursion, branching, or approximations required.



                        Instead, it looks like you are trying to compute the entries B[i] starting from B[a.length]. This leads to a more complicated structure where you make recursive calls, and re-compute the same values B[i] multiple times, as pointed out also by @vnp's answer.



                        Once you have figured out how to fill the B array in this way, a further improvement is realizing that you only need to keep the last three values B[k], B[k-1], B[k-2] at each step (and possibly also the partial sum a[k-2] + ... + a[a.length]). This gives a solution in O(1) space.



                        If you want to compare with another famous function in which f(n) depends on its previous values, what you wrote is like computing Fibonacci numbers recursively via return fibonacci(n-1) + fibonacci(n-2). What I suggest above is computing iteratively f[0], f[1], f[2], ... starting from f[0].






                        share|improve this answer










                        New contributor



                        Federico Poloni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.





                        $endgroup$












                        • $begingroup$
                          fantastic answer and explanation. +1
                          $endgroup$
                          – Khan Power
                          Jun 17 at 16:47













                        7












                        7








                        7





                        $begingroup$

                        The natural way to tackle this problem (as in many similar games) is starting from the final position.



                        Let B[k] be the maximum score that Player 1 can get if the game starts with only the last k stones left. B[1], B[2], B[3] are initial values that can be computed directly (just take all remaining stones), and then you can fill in B[4], B[5], B[6], ... in this order, since B[k] only depends on B[k-1], B[k-2], B[k-3]; so you can write your code as a loop for k=4,5,6,..., a.length. The resulting algorithm is linear, without no recursion, branching, or approximations required.



                        Instead, it looks like you are trying to compute the entries B[i] starting from B[a.length]. This leads to a more complicated structure where you make recursive calls, and re-compute the same values B[i] multiple times, as pointed out also by @vnp's answer.



                        Once you have figured out how to fill the B array in this way, a further improvement is realizing that you only need to keep the last three values B[k], B[k-1], B[k-2] at each step (and possibly also the partial sum a[k-2] + ... + a[a.length]). This gives a solution in O(1) space.



                        If you want to compare with another famous function in which f(n) depends on its previous values, what you wrote is like computing Fibonacci numbers recursively via return fibonacci(n-1) + fibonacci(n-2). What I suggest above is computing iteratively f[0], f[1], f[2], ... starting from f[0].






                        share|improve this answer










                        New contributor



                        Federico Poloni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.





                        $endgroup$



                        The natural way to tackle this problem (as in many similar games) is starting from the final position.



                        Let B[k] be the maximum score that Player 1 can get if the game starts with only the last k stones left. B[1], B[2], B[3] are initial values that can be computed directly (just take all remaining stones), and then you can fill in B[4], B[5], B[6], ... in this order, since B[k] only depends on B[k-1], B[k-2], B[k-3]; so you can write your code as a loop for k=4,5,6,..., a.length. The resulting algorithm is linear, without no recursion, branching, or approximations required.



                        Instead, it looks like you are trying to compute the entries B[i] starting from B[a.length]. This leads to a more complicated structure where you make recursive calls, and re-compute the same values B[i] multiple times, as pointed out also by @vnp's answer.



                        Once you have figured out how to fill the B array in this way, a further improvement is realizing that you only need to keep the last three values B[k], B[k-1], B[k-2] at each step (and possibly also the partial sum a[k-2] + ... + a[a.length]). This gives a solution in O(1) space.



                        If you want to compare with another famous function in which f(n) depends on its previous values, what you wrote is like computing Fibonacci numbers recursively via return fibonacci(n-1) + fibonacci(n-2). What I suggest above is computing iteratively f[0], f[1], f[2], ... starting from f[0].







                        share|improve this answer










                        New contributor



                        Federico Poloni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.








                        share|improve this answer



                        share|improve this answer








                        edited Jun 17 at 13:31





















                        New contributor



                        Federico Poloni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.








                        answered Jun 17 at 9:34









                        Federico PoloniFederico Poloni

                        1734 bronze badges




                        1734 bronze badges




                        New contributor



                        Federico Poloni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.




                        New contributor




                        Federico Poloni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.













                        • $begingroup$
                          fantastic answer and explanation. +1
                          $endgroup$
                          – Khan Power
                          Jun 17 at 16:47
















                        • $begingroup$
                          fantastic answer and explanation. +1
                          $endgroup$
                          – Khan Power
                          Jun 17 at 16:47















                        $begingroup$
                        fantastic answer and explanation. +1
                        $endgroup$
                        – Khan Power
                        Jun 17 at 16:47




                        $begingroup$
                        fantastic answer and explanation. +1
                        $endgroup$
                        – Khan Power
                        Jun 17 at 16:47











                        3












                        $begingroup$

                        I am not too happy about the variable name currSum, it is hard to see the meaning of this variable from the name alone.



                        Consider takenValue or something similar as a variable name.



                        Note that



                        a[start] + (sum - currSum - a[start])



                        Simplifies to



                        sum - currSum



                        And similarily for the other cases so;



                         int v1 = a[start] + (sum - currSum - a[start]) - 
                        maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

                        int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
                        maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

                        int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
                        maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


                        simplifies to



                         int v1 = sum - currSum - 
                        maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

                        int v2 = sum - currSum -
                        maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

                        int v3 = sum - currSum -
                        maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


                        We should also try to capture the meaning of a[start]+...a[start+n], we can do this by introducing a new variable takenInCurrentStep



                        Also



                         int val = 0;
                        for (int i=start; i<len; i++)
                        val += a[i];

                        return val;


                        Is needlessly complicated. We can write this as :



                         return sum-currSum;


                        Bringing this all together :



                         public static int maxPlayer1(int[] a, int takenValue, int sum, int start, int len) 
                        if (len-start <=3)
                        return sum-takenValue;


                        int valueTakenInCurrentStep = 0;
                        int lasttokensTakenInCurrentStep = start;
                        int valueTakenInCurrentStep = a[lasttokensTakenInCurrentStep];

                        int v1 = sum - takenValue -
                        maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                        int lasttokensTakenInCurrentStep ++;
                        int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];

                        int v2 = sum - takenValue -
                        maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                        int lasttokensTakenInCurrentStep ++;
                        int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];
                        int v3 = sum - takenValue -
                        maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                        return Math.max(v1, Math.max(v2, v3));

                        }


                        The algorithm can be described as;



                        We have a method that calculates the maximum that the current player can get from the remaining of the game. The method takes the value of all the tokens, the value of the tokens that are no longer available, the value of all tokens, the index of the first currently available token, and the total number of tokens.



                        It works by if there are 3 or less tokens left return the value of the remaining tokens, which is equal to the value of all tokens minus the value of the tokens already taken.
                        If there are more than 3 tokens return the maximum of the value of remaining tokens minus the amount that the other player gets if current player takes 1,2 or 3 tokens.



                        This is a correct algorithm, and we can prove this by incursion.






                        share|improve this answer









                        $endgroup$

















                          3












                          $begingroup$

                          I am not too happy about the variable name currSum, it is hard to see the meaning of this variable from the name alone.



                          Consider takenValue or something similar as a variable name.



                          Note that



                          a[start] + (sum - currSum - a[start])



                          Simplifies to



                          sum - currSum



                          And similarily for the other cases so;



                           int v1 = a[start] + (sum - currSum - a[start]) - 
                          maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

                          int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
                          maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

                          int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
                          maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


                          simplifies to



                           int v1 = sum - currSum - 
                          maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

                          int v2 = sum - currSum -
                          maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

                          int v3 = sum - currSum -
                          maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


                          We should also try to capture the meaning of a[start]+...a[start+n], we can do this by introducing a new variable takenInCurrentStep



                          Also



                           int val = 0;
                          for (int i=start; i<len; i++)
                          val += a[i];

                          return val;


                          Is needlessly complicated. We can write this as :



                           return sum-currSum;


                          Bringing this all together :



                           public static int maxPlayer1(int[] a, int takenValue, int sum, int start, int len) 
                          if (len-start <=3)
                          return sum-takenValue;


                          int valueTakenInCurrentStep = 0;
                          int lasttokensTakenInCurrentStep = start;
                          int valueTakenInCurrentStep = a[lasttokensTakenInCurrentStep];

                          int v1 = sum - takenValue -
                          maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                          int lasttokensTakenInCurrentStep ++;
                          int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];

                          int v2 = sum - takenValue -
                          maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                          int lasttokensTakenInCurrentStep ++;
                          int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];
                          int v3 = sum - takenValue -
                          maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                          return Math.max(v1, Math.max(v2, v3));

                          }


                          The algorithm can be described as;



                          We have a method that calculates the maximum that the current player can get from the remaining of the game. The method takes the value of all the tokens, the value of the tokens that are no longer available, the value of all tokens, the index of the first currently available token, and the total number of tokens.



                          It works by if there are 3 or less tokens left return the value of the remaining tokens, which is equal to the value of all tokens minus the value of the tokens already taken.
                          If there are more than 3 tokens return the maximum of the value of remaining tokens minus the amount that the other player gets if current player takes 1,2 or 3 tokens.



                          This is a correct algorithm, and we can prove this by incursion.






                          share|improve this answer









                          $endgroup$















                            3












                            3








                            3





                            $begingroup$

                            I am not too happy about the variable name currSum, it is hard to see the meaning of this variable from the name alone.



                            Consider takenValue or something similar as a variable name.



                            Note that



                            a[start] + (sum - currSum - a[start])



                            Simplifies to



                            sum - currSum



                            And similarily for the other cases so;



                             int v1 = a[start] + (sum - currSum - a[start]) - 
                            maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

                            int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
                            maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

                            int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
                            maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


                            simplifies to



                             int v1 = sum - currSum - 
                            maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

                            int v2 = sum - currSum -
                            maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

                            int v3 = sum - currSum -
                            maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


                            We should also try to capture the meaning of a[start]+...a[start+n], we can do this by introducing a new variable takenInCurrentStep



                            Also



                             int val = 0;
                            for (int i=start; i<len; i++)
                            val += a[i];

                            return val;


                            Is needlessly complicated. We can write this as :



                             return sum-currSum;


                            Bringing this all together :



                             public static int maxPlayer1(int[] a, int takenValue, int sum, int start, int len) 
                            if (len-start <=3)
                            return sum-takenValue;


                            int valueTakenInCurrentStep = 0;
                            int lasttokensTakenInCurrentStep = start;
                            int valueTakenInCurrentStep = a[lasttokensTakenInCurrentStep];

                            int v1 = sum - takenValue -
                            maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                            int lasttokensTakenInCurrentStep ++;
                            int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];

                            int v2 = sum - takenValue -
                            maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                            int lasttokensTakenInCurrentStep ++;
                            int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];
                            int v3 = sum - takenValue -
                            maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                            return Math.max(v1, Math.max(v2, v3));

                            }


                            The algorithm can be described as;



                            We have a method that calculates the maximum that the current player can get from the remaining of the game. The method takes the value of all the tokens, the value of the tokens that are no longer available, the value of all tokens, the index of the first currently available token, and the total number of tokens.



                            It works by if there are 3 or less tokens left return the value of the remaining tokens, which is equal to the value of all tokens minus the value of the tokens already taken.
                            If there are more than 3 tokens return the maximum of the value of remaining tokens minus the amount that the other player gets if current player takes 1,2 or 3 tokens.



                            This is a correct algorithm, and we can prove this by incursion.






                            share|improve this answer









                            $endgroup$



                            I am not too happy about the variable name currSum, it is hard to see the meaning of this variable from the name alone.



                            Consider takenValue or something similar as a variable name.



                            Note that



                            a[start] + (sum - currSum - a[start])



                            Simplifies to



                            sum - currSum



                            And similarily for the other cases so;



                             int v1 = a[start] + (sum - currSum - a[start]) - 
                            maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

                            int v2 = a[start] + a[start+1] + (sum - currSum - a[start] - a[start+1]) -
                            maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

                            int v3 = a[start] + a[start+1] + a[start+2] + (sum - currSum - a[start] - a[start+1] - a[start+2]) -
                            maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


                            simplifies to



                             int v1 = sum - currSum - 
                            maxPlayer1(a, currSum + a[start], sum, start + 1, a.length);

                            int v2 = sum - currSum -
                            maxPlayer1(a, currSum + a[start] + a[start+1], sum, start + 2, a.length);

                            int v3 = sum - currSum -
                            maxPlayer1(a, currSum + a[start] + a[start+1] + a[start+2], sum, start + 3, a.length);


                            We should also try to capture the meaning of a[start]+...a[start+n], we can do this by introducing a new variable takenInCurrentStep



                            Also



                             int val = 0;
                            for (int i=start; i<len; i++)
                            val += a[i];

                            return val;


                            Is needlessly complicated. We can write this as :



                             return sum-currSum;


                            Bringing this all together :



                             public static int maxPlayer1(int[] a, int takenValue, int sum, int start, int len) 
                            if (len-start <=3)
                            return sum-takenValue;


                            int valueTakenInCurrentStep = 0;
                            int lasttokensTakenInCurrentStep = start;
                            int valueTakenInCurrentStep = a[lasttokensTakenInCurrentStep];

                            int v1 = sum - takenValue -
                            maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                            int lasttokensTakenInCurrentStep ++;
                            int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];

                            int v2 = sum - takenValue -
                            maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                            int lasttokensTakenInCurrentStep ++;
                            int valueTakenInCurrentStep = valueTakenInCurrentStep + a[lasttokensTakenInCurrentStep ];
                            int v3 = sum - takenValue -
                            maxPlayer1(a, takenValue+ valueTakenInCurrentStep, sum, lasttokensTakenInCurrentStep+1 , a.length);

                            return Math.max(v1, Math.max(v2, v3));

                            }


                            The algorithm can be described as;



                            We have a method that calculates the maximum that the current player can get from the remaining of the game. The method takes the value of all the tokens, the value of the tokens that are no longer available, the value of all tokens, the index of the first currently available token, and the total number of tokens.



                            It works by if there are 3 or less tokens left return the value of the remaining tokens, which is equal to the value of all tokens minus the value of the tokens already taken.
                            If there are more than 3 tokens return the maximum of the value of remaining tokens minus the amount that the other player gets if current player takes 1,2 or 3 tokens.



                            This is a correct algorithm, and we can prove this by incursion.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jun 17 at 11:26









                            TaemyrTaemyr

                            9055 silver badges9 bronze badges




                            9055 silver badges9 bronze badges



























                                draft saved

                                draft discarded
















































                                Thanks for contributing an answer to Code Review Stack Exchange!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid


                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.

                                Use MathJax to format equations. MathJax reference.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f222413%2fwhat-is-the-maximum-that-player-1-can-win%23new-answer', 'question_page');

                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Get product attribute by attribute group code in magento 2get product attribute by product attribute group in magento 2Magento 2 Log Bundle Product Data in List Page?How to get all product attribute of a attribute group of Default attribute set?Magento 2.1 Create a filter in the product grid by new attributeMagento 2 : Get Product Attribute values By GroupMagento 2 How to get all existing values for one attributeMagento 2 get custom attribute of a single product inside a pluginMagento 2.3 How to get all the Multi Source Inventory (MSI) locations collection in custom module?Magento2: how to develop rest API to get new productsGet product attribute by attribute group code ( [attribute_group_code] ) in magento 2

                                Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

                                Magento 2.3: How do i solve this, Not registered handle, on custom form?How can i rewrite TierPrice Block in Magento2magento 2 captcha not rendering if I override layout xmlmain.CRITICAL: Plugin class doesn't existMagento 2 : Problem while adding custom button order view page?Magento 2.2.5: Overriding Admin Controller sales/orderMagento 2.2.5: Add, Update and Delete existing products Custom OptionsMagento 2.3 : File Upload issue in UI Component FormMagento2 Not registered handleHow to configured Form Builder Js in my custom magento 2.3.0 module?Magento 2.3. How to create image upload field in an admin form