Progress: Updated the rules after some discussions in The Nineteenth Byteagain, and also add the timed function to the bots.
Here is a twist -- R. L. Hutchings proved that announcing a prime number as the first play provides a winning strategy for the first player, although the detail of the strategy is not yet known. So I put a restriction here: the first player cannot announce a prime number in the first step. Now the first two numbers will be generated randomly by the driver at the beginning and will be coprime. No more restriction on prime numbers now.
A bot playing the game will have to implement a Python 3 class, extending TimedBot
, with two methods: announce()
and learn()
. announce()
should receive a list of numbers (possibly empty) and return a single integer, and learn()
should receive two integers (id of the first move and second move) and the complete list of the numbers in the last game played.
class SampleBot(TimedBot): # must not be changed.
def __init__(self, id):
super().__init__() # must not be changed.
self.id = id
def announce(self, list):
import random
return random.randint(1, 101)
def learn(self, first, second, list):
pass
class SampleBotTimedBot:
def __init__(self, id):
self.idtime = id20.0
def announcetimed(self, listfunc):
import random
returndef random.randintf(1self, 100001*args)
:
def learn(self, first, second, list):
import time
pass
# very inefficient
def islinearcomb(n, l):
if lena = time.time(l):
for i in range(0, nb += 1func(self, l[0]*args):
ifself.time i-= ==(time.time() n:- a)
print(self.time)
return [n // l[0]]
return b
elifreturn lenf
class SampleBot(lTimedBot):
> 1 def __init__(self, id):
super().__init__()
islself.id = islinearcomb(n -id
i, l[1:])
@TimedBot.timed
def announce(self, list):
ifimport isl:random
return random.randint(1, 100001)
@TimedBot.timed
def learn(self, returnfirst, [isecond, //list):
l[0]] + isl
return Nonepass
# very inefficient
def gcdislinearcomb(an, bl):
if a < blen(l):
returnfor gcdi in range(b0, an + 1, l[0]):
elif not b:
if i return== an:
else:
return gcd(b, a % b)
defreturn isprime(n):[n // l[0]]
if n % 2 == 0:
elif len(l) > 1:
return False
i = 3
while i * iisl <== islinearcomb(n - i, l[1:])
if n % i == 0 if isl:
return False
return i[i +=// 2l[0]] + isl
return TrueNone
lose = -1
turn = 0
nums = []
bots = [SampleBot(0), SampleBot(1)] # replace with your bots here.
import random
while (len(nums) < 2):
numsa, b, c, d = [randomrandom.randint(1000001, 99999910), random.randint(1000001, 99999910)], random.randint(1, 10), random.randint(1, 10)
if gcd2**a * 3**b != 2**c * 3**d and 2**a * 3**b > 100000 and 2**c * 3**d > 100000 and 2**min(nums[0]a,c) nums[1]* 3**min(b,d) > 112:
nums = [][2**a * 3**b, 2**c * 3**d]
while lose < 0:
v = bots[turn].announce(nums)
print("{0}({1}) announced {2}".format(type(bots[turn]).__name__, bots[turn].id, v))
w = islinearcomb(v, nums)
if w:
str = ""
for i in range(0, len(nums)):
if i:
str += "+"
str += "{0}*{1}".format(nums[i], w[i] if i < len(w) else 0)
print("{0}({1}) announced {2} that is equal to {3}".format(type(bots[turn]).__name__, bots[turn].id, v, str))
lose = turn
elif v == 1:
print("{0}({1}) announced 1".format(type(bots[turn]).__name__, bots[turn].id))
lose = turn
nums += [v]
turn = 1 - turn
print("{0}({1}) wins".format(type(bots[1 - lose]).__name__, bots[1 - lose].id))
Both methods should be finished promptly withinEach bot will have 20 seconds of time for deciding a move todo: adjustments
. FailingRunning out time during the move results in a lose, and failing to finish a method within the requirement time20 seconds will lead to disqualification and rerun of all 100 rounds with the remaining bots.