calculations¶
The Nim Game calculation functions
This module defines the functions that are needed to calculate moves and
decisions in a Mixin
for the Nim
class.
- class calculations.Mixin[source]¶
Class to implement the Nim game calculations
This Mixin is used as an ancestor class for
Nim
, so that we can define methods here, in a separate module.The term “nimsum” (Grundy value or nim-value), used here, is the Nimber that the game is equivalent to. This number represents the current state of the game.
The importance of nimsum is whether it is zero or not. If nimsum is not zero, it can be changed to zero by the right move of the next player. If the nimsum is zero, the next move will change it to non-zero, whatever the move is. This way, the player who moves in a way to create zero nimsum is the one who drives the game and can win it.
In case of “misère” type of game, there is a point in the course of the game where the strategy must reverse, because we want to opponent to take the last coin. This point is the beginning of the “end-game”. In the end-game, all moves alternate the nimsum between 0 and 1. The winning player changes the nimsum to 1 and the losing player has no other choise but changing it to zero and ultimately taking the last coin.
- all_one_heaps() bool [source]¶
Checks whether all non-zero heaps have 1 single coin
It uses the functools.reduce() on the heaps list, with a True initializing value and keep it true as long as the number of coins is at most one.
- Returns
Whether all relevant heaps have 1 single coin
- figure_out_best_move() Move [source]¶
Figure out what to move so that we get into a winning position
First handle the situation when all heaps only have 1 coin. If so, there is nothing to think about, just take that 1 coin from a heap randomly.
Then check whether there is only 1 heap with more than 1 coins. This is the indicator for the end-game reversal in the “misère” type. The winning strategy here is to leave odd numbers of 1-coin heaps for the opponent. So, if the number of heaps with 1 coin is odd, take all coins from the heap that has more than 1 coin. If it is even, take all but 1 coin. Either way, this makes sure that odd number of 1-coin heaps are left for the opponent.
Otherwise, we are in the middle of the game, so figure out the all-heap nimsum. If it is zero, the player in this current turn is in a losing position, because whatever we do we create a non-zero nimsum that the opponent can change to zero nimsum again in its turn. So, having no better option, we just take a random number of coins from a random heap and hope that the opponent makes a mistake.
If nimsum is not zero, it can be made zero by removing a cretain number of coins from the right heap. Check each heap and calculate the “target” number of coins, to null the nimsum. E.g. if the nimsum is 7 (binary 111), we need to remove all 3 binary digits, i.e. the 4, 2 and 1, without changing any other binary digits, e.g. the 8. If a given heap contains e.g. 9 coins (binary 1001), the “target” would be the 7 \(\oplus\) 9:
1001 0111 ---- 1110 => decimal 14
As we cannot remove 14 coins from a heap where there are 9 coins, this is not a suitable heap to remove coins from. So, go on until finding a suitable heap. Theoretically, there must be at least 1 suitable heap.
- Returns
From which heap and how many coins are to be removed in the coming move
- get_nimsum() int [source]¶
Calcualte the nimsum of the set of heaps
It uses the functools.reduce() on the heaps list, with a 0 initializing value and uses XOR for the coin counts of the heaps.
- Returns
The nimsum of the heap-set
- get_random_move() Move [source]¶
Figure out a random but valid move
This method is used when the algorithm does not care what to move. Just figure out a random but valid move.
- Returns
From which heap and how many coins are to be removed in the coming move
- is_winning_for_next() bool [source]¶
Is the current status good for the player having the next turn?
Usually non-zero nimsum is the winning status, so that the player can change it to zero nimsum. This way this player can force the other player to make non-winning move, i.e. creating non-zero nimsum, which this player can change to zero nimsum again, end so on.
However, in “misère” type game, the strategy changes in the end-game moves. When all heaps only have 1 coin left, the winning status is when nimsum is zero. I.e. the all-heaps-has-one-coin reverses the bool nimsum. The boolean reversal is done with an XOR.
- Returns
Whether the current status is good for the player having the next turn
- make_good_choice() bool [source]¶
Figures out whether to make a good decision or make an error
The required error rate indicates how bad decisions the Computer is to make. The higher the error rate percentage the higher the possibility that the Computer makes a bad move/decision. If error_rate is 0, this function always returns True, i.e. the Computer always makes a good decision. If error_rate is 100, the Computer always makes a bad decision.
- Returns
False forces to make the bad choise