[Interesting question] A game in which several piles of stones are picked up in turn, and whoever picks up the last stone loses

a topic description

There are three piles of stones, 7, 5, and 3 each, and two people take turns to do the following:

    Choose a pile (the number of stones is not 0);

    Take at least one and at most all stones from the pile;

Until someone takes the last stone, that person loses.

Two ideas

At that time, it was intuition that such a topic had a high probability of winning first, but today I have the opportunity to write it in code.

1. In the case of a small number of chess pieces, a violent solution can be used.

2. If based on the current situation, the opponent must lose, then the current player must win; otherwise, the current player must lose. This black-and-white logic is explained as follows:

    We can gradually add stone builds up from the final case to the initial case. For example, the situation of 1-0-0 is a situation where the first mover will lose, then all the situations that can form a 1-0-0 in one operation are considered to be the first mover and the loser; if a certain situation cannot be reduced by reducing the stone into any first mover will lose. In other words, no matter how you move in this situation, it leaves the opponent a situation where the first mover will win. In this case, the first mover will lose. .

3. Generate a situation code based on the situation to avoid double calculation and prune. (Actual effect: reduce the number of recursive calls from 98708 to 5592)

three code

 
 
 
 
# -*- coding:UTF-8 -*-
 cnt = 0 # Counter, look at the number of times the function is called
 deadSet = set() # Because it involves some repeated judgments, use a set to record the inevitable loss and reduce the number of iterations
 def genDeadNum (curList): # Convert the situation into situation code 
    return "-" .join([str(x) for x in sorted(curList , reverse = True )])
 def decide (a):
     global cnt
    aOld = a[:] # Save our situation and the situation after our operation
 for pileIdx in xrange( 0 , len(a)): # Pick a pile of stones
 if a[pileIdx] == 0 : # If there are no stones, Skip
 continue
         else :                        
            temp = a[pileIdx] # Backup original quantity
 for remainNums in xrange( 0 ,   temp): # Select the remaining quantity after taking away
 print pileIdx , remainNums                            
                a[pileIdx] = remainNums
                if sum(a) == 0 : # If I can't get it all, it means I lost, let's skip the
 continue
                 else : # There are still stones, see the opponent's situation
 testNum = genDeadNum(a) # Let's generate the corresponding situation first The code
 if testNum in deadSet or decide(a) == 0 : # If the corresponding situation is to lose, or we find the result is 0 after iteration, the opponent must lose, we must win, return 1
 print "From" , aOld , " to " , a                                                                                    
                        a[pileIdx] = temp
                        cnt += 1
 return 1 # Return the winning code 1
 a[pileIdx] = temp # After traversing the possibility of taking the pile of stones, remember to restore the initial state of the pile of stones
 print "When the piles like " , a , "I cannot win!" # If all the above traversal can't find the means to win, it means that we must lose.
deadNum = genDeadNum(a) # Generate a situation code that will fail to be added to the death set
 deadSet.add(deadNum)                                                
    cnt += 1
 return 0 # must return 0
 if __name__ == "__main__" :    

    a= [7, 5, 3]
    res = decide(a)
    print res, cnt
    print list(deadSet)
 
 

It can be seen that there are only the following situations in which the first mover will lose in the end

'3-2-1', '6-4-2', '1-0-0', '1-1-1', '3-3-0', '5-5-0', '2-2-0', '6-5-3', '4-4-0', '5-4-1'

For example: Our first step is to convert 7-5-3 into 6-5-3, giving the opponent a certain defeat situation, and then everyone can imagine the future situation by themselves.

Four extension, whoever picks up the last one wins the game

Modify the rules so that whoever gets the last one wins

Then it becomes an XOR problem. Suppose two scenarios:

1. The number of three piles of stones is XORed to 0

2. The number of three piles of stones is non-zero after XOR

Arbitrary fetching of stones in case 1 will cause the remaining stones to be converted to case 2

For the case of case 2, it must be possible to use a method of taking stones to convert the remaining stones into case 1

The one who wins in the end is the one who converts the situation to situation 1 (0-0-0)


In this way, if the initial situation is case 2, the person who starts first only needs to be responsible for converting case 2 to case 1 for each operation.

If the initial situation is Situation 1, then the first player is forced to give the second player a Situation 2, and the second player can win through the strategy in the previous sentence.

The code can be slightly modified, omitted.

The must-lose cases given by the code are as follows, which is a list of all possible cases 1.

['3-2-1', '6-4-2', '1-1-0', '5-4-1', '5-5-0', '2-2-0', '6-5-3', '4-4-0', '3-3-0']







Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324650811&siteId=291194637