71 lines
1.6 KiB
Python
71 lines
1.6 KiB
Python
|
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)
|
||
|
|