|  | 
|  | 1 | +""" | 
|  | 2 | +Project Euler Problem 301: https://projecteuler.net/problem=301 | 
|  | 3 | +
 | 
|  | 4 | +Problem Statement: | 
|  | 5 | +Nim is a game played with heaps of stones, where two players take | 
|  | 6 | +it in turn to remove any number of stones from any heap until no stones remain. | 
|  | 7 | +
 | 
|  | 8 | +We'll consider the three-heap normal-play version of | 
|  | 9 | +Nim, which works as follows: | 
|  | 10 | +- At the start of the game there are three heaps of stones. | 
|  | 11 | +- On each player's turn, the player may remove any positive | 
|  | 12 | + number of stones from any single heap. | 
|  | 13 | +- The first player unable to move (because no stones remain) loses. | 
|  | 14 | +
 | 
|  | 15 | +If (n1, n2, n3) indicates a Nim position consisting of heaps of size | 
|  | 16 | +n1, n2, and n3, then there is a simple function, which you may look up | 
|  | 17 | +or attempt to deduce for yourself, X(n1, n2, n3) that returns: | 
|  | 18 | +- zero if, with perfect strategy, the player about to | 
|  | 19 | + move will eventually lose; or | 
|  | 20 | +- non-zero if, with perfect strategy, the player about | 
|  | 21 | + to move will eventually win. | 
|  | 22 | +
 | 
|  | 23 | +For example X(1,2,3) = 0 because, no matter what the current player does, | 
|  | 24 | +the opponent can respond with a move that leaves two heaps of equal size, | 
|  | 25 | +at which point every move by the current player can be mirrored by the | 
|  | 26 | +opponent until no stones remain; so the current player loses. To illustrate: | 
|  | 27 | +- current player moves to (1,2,1) | 
|  | 28 | +- opponent moves to (1,0,1) | 
|  | 29 | +- current player moves to (0,0,1) | 
|  | 30 | +- opponent moves to (0,0,0), and so wins. | 
|  | 31 | +
 | 
|  | 32 | +For how many positive integers n <= 2^30 does X(n,2n,3n) = 0? | 
|  | 33 | +""" | 
|  | 34 | + | 
|  | 35 | + | 
|  | 36 | +def solution(exponent: int = 30) -> int: | 
|  | 37 | + """ | 
|  | 38 | + For any given exponent x >= 0, 1 <= n <= 2^x. | 
|  | 39 | + This function returns how many Nim games are lost given that | 
|  | 40 | + each Nim game has three heaps of the form (n, 2*n, 3*n). | 
|  | 41 | + >>> solution(0) | 
|  | 42 | + 1 | 
|  | 43 | + >>> solution(2) | 
|  | 44 | + 3 | 
|  | 45 | + >>> solution(10) | 
|  | 46 | + 144 | 
|  | 47 | + """ | 
|  | 48 | + # To find how many total games were lost for a given exponent x, | 
|  | 49 | + # we need to find the Fibonacci number F(x+2). | 
|  | 50 | + fibonacci_index = exponent + 2 | 
|  | 51 | + phi = (1 + 5 ** 0.5) / 2 | 
|  | 52 | + fibonacci = (phi ** fibonacci_index - (phi - 1) ** fibonacci_index) / 5 ** 0.5 | 
|  | 53 | + | 
|  | 54 | + return int(fibonacci) | 
|  | 55 | + | 
|  | 56 | + | 
|  | 57 | +if __name__ == "__main__": | 
|  | 58 | + print(f"{solution() = }") | 
0 commit comments