from functools import lru_cache @lru_cache def x_naiv(s): zcount = s.count(0) if zcount == 3: return 0 elif zcount == 2: return 1 elif zcount == 1: sl = list(s) sl.remove(0) if sl[0] == sl[1]: return 0 s = list(s) for i in range(len(s)): for v in range(1, s[i] + 1): ns = list(s) ns[i] -= v if x_naiv(tuple(sorted(ns))) == 0: # Other player loses. return 1 return 0 def x_nim_sum(s): """ I wasn't able to deduce this myself quickly and looked it up instead. """ return 0 if (s[0] ^ s[1] ^ s[2]) == 0 else 1 def test_nim_functions(): assert(x_naiv(tuple([0, 0, 0])) == 0) assert(x_naiv(tuple([1, 0, 0])) == 1) assert(x_naiv(tuple([1, 1, 0])) == 0) assert(x_naiv(tuple([1, 1, 1])) == 1) assert(x_naiv(tuple([1, 2, 3])) == 0) for n1 in range(0, 8): for n2 in range(1, n1 + 1): for n3 in range(1, n2 + 1): s = tuple([n1, n2, n3]) assert x_naiv(s) == x_nim_sum(s) def euler_301(): test_nim_functions() # log(2**30, 10) ~= 9 -> 1 billion easy brute force # Probably a more efficient computation is possible by counting the permutations # where all binary digits are zero. # 0 0 0 -> 0 # 0 0 1 -> 0 # 0 1 1 -> 0 r = 0 for n in range(1, 2**30 + 1): s = tuple([n, 2 * n, 3 * n]) xr = x_nim_sum(s) if xr == 0: r += 1 return r if __name__ == "__main__": solution = euler_301() print("e301.py: " + str(solution)) # assert(solution == 0)