class Game(object): def __init__(self, gold, silver, timecontrol=None, start_position=None, strict_setup=True, min_timeleft=None): self.engines = (gold, silver) try: self.timecontrol = timecontrol[0] self.side_tc = timecontrol except TypeError: self.timecontrol = timecontrol self.side_tc = [timecontrol, timecontrol] self.reserves = [None, None] if timecontrol: for side, eng in enumerate(self.engines): if not self.side_tc[side]: continue self.reserves[side] = self.side_tc[side].reserve eng.setoption("tcmove", self.side_tc[side].move) eng.setoption("tcreserve", self.side_tc[side].reserve) eng.setoption("tcpercent", self.side_tc[side].percent) eng.setoption("tcmax", self.side_tc[side].max_reserve) eng.setoption("tcturns", self.side_tc[side].turn_limit) eng.setoption("tctotal", self.side_tc[side].time_limit) eng.setoption("tcturntime", self.side_tc[side].max_turntime) for eng in self.engines: eng.newgame() if start_position: eng.setposition(start_position) resps = eng.isready() side = "gs" [self.engines.index(eng)] eng_name = eng.ident["name"] for response in resps: if response.type == "info": log.info("%s (%s) info: %s", eng_name, side, response.message) elif response.type == "log": log.info("%s (%s) log: %s", eng_name, side, response.message) else: log.warn( "Unexpected response while initializing %s (%s) (%s).", eng_name, side, response.type) self.insetup = False self.position = start_position if not start_position: self.insetup = True self.position = Position(Color.GOLD, 4, BLANK_BOARD) self.strict_setup = strict_setup self.min_timeleft = min_timeleft self.movenumber = 1 self.limit_winner = 1 self.moves = [] self.repetition_count = defaultdict(int) self.result = None def play(self): if self.result: raise RuntimeError("Tried to play a game that was already played.") starttime = time.time() while not self.position.is_end_state() or self.insetup: try: result = self.play_next_move(starttime) if result: break except IllegalMove as e: log.info("Illegal move played: %s" % e) result = (self.position.color ^ 1, "i") break if not result: if self.position.is_goal(): result = (0 - min(self.position.is_goal(), 0), "g") elif self.position.is_rabbit_loss(): result = (0 - min(self.position.is_rabbit_loss(), 0), "e") else: # immobilization assert len(self.position.get_steps()) == 0 result = (self.position.color ^ 1, "m") self.result = result return result def play_next_move(self, starttime): position = self.position side = position.color engine = self.engines[side] tc = self.side_tc[side] if tc: if tc.time_limit: endtime_limit = starttime + tc.time_limit if engine.protocol_version == 0: if self.reserves[0] is not None: engine.setoption("wreserve", int(self.reserves[0])) if self.reserves[1] is not None: engine.setoption("breserve", int(self.reserves[1])) engine.setoption("tcmoveused", 0) if self.reserves[0] is not None: engine.setoption("greserve", int(self.reserves[0])) if self.reserves[1] is not None: engine.setoption("sreserve", int(self.reserves[1])) engine.setoption("moveused", 0) movestart = time.time() engine.go() if tc: timeout = movestart + tc.move + self.reserves[side] if tc.max_turntime and movestart + tc.max_turntime < timeout: timeout = movestart + tc.max_turntime if tc.time_limit and endtime_limit < timeout: timeout = endtime_limit else: timeout = None waittime = None resp = None stopsent = False stoptime = None if timeout and self.min_timeleft: stoptime = timeout - self.min_timeleft while True: now = time.time() if stoptime and not stopsent and now >= stoptime: # try and get a move before time runs out engine.stop() log.info("Engine sent stop command to prevent timeout") stopsent = True if timeout and now > timeout: if not stopsent: engine.stop() break if timeout: waittime = timeout - now if stoptime and not stopsent and now + waittime > stoptime: waittime = max(0, (stoptime - now) + 0.2) try: resp = engine.get_response(waittime) if resp.type == "bestmove": break if resp.type == "info": log.info("%s (%s) info: %s", engine.ident["name"], "gs" [side], resp.message) elif resp.type == "log": log.info("%s (%s) log: %s", engine.ident["name"], "gs" [side], resp.message) except socket.timeout: pass moveend = time.time() if tc and moveend > timeout: if tc.time_limit and endtime_limit < moveend: return (self.limit_winner, "s") else: return (side ^ 1, "t") if not resp or resp.type != "bestmove": # pragma: no cover raise RuntimeError( "Stopped waiting without a timeout or a move") if tc: if not self.insetup: reserve_change = tc.move - (moveend - movestart) if reserve_change > 0: # if we are adding to the reserve only apply the # percentage specified by the time control reserve_change *= tc.percent / 100.0 self.reserves[side] += reserve_change if tc.max_reserve: self.reserves[side] = min(self.reserves[side], tc.max_reserve) move = resp.move if move.lower() == "resign": return (side ^ 1, "r") self.moves.append("%d%s %s" % (self.movenumber, "gs" [position.color], move)) if self.insetup: position = position.do_move_str( move, strict_checks=self.strict_setup) else: position = position.do_move_str(move) if position.bitBoards == self.position.bitBoards: raise IllegalMove("Tried move that did not change the position, %s" % move) self.repetition_count[position] += 1 if self.repetition_count[position] > 2: raise IllegalMove("Tried move resulting in a 3rd time repetition") self.position = position if position.color == Color.GOLD: self.movenumber += 1 log.debug("position:\n%s", position.board_to_str()) for eng in self.engines: eng.makemove(move) if self.insetup and side == Color.SILVER: self.insetup = False if not self.insetup: bstr = position.board_to_str("short") gp = 0 for p in "EMHDCR": gp += bstr.count(p) sp = 0 for p in "emhdcr": sp += bstr.count(p) if gp > sp: limit_winner = 0 elif sp > gp: limit_winner = 1 if tc and tc.turn_limit and self.movenumber > tc.turn_limit: return (limit_winner, "s")
def playgame(gold_eng, silver_eng, timecontrol=None, position=None): engines = (gold_eng, silver_eng) if timecontrol: time_incr = timecontrol['move'] reserves = [0, 0] reserves[0] = reserves[1] = timecontrol['reserve'] reserve_per = timecontrol['percent'] / 100.0 reserve_max = timecontrol['max'] max_moves = timecontrol['turns'] max_gametime = timecontrol['total'] max_turn = timecontrol['turntime'] for eng in engines: eng.setoption("tcmove", time_incr) eng.setoption("tcreserve", timecontrol['reserve']) eng.setoption("tcpercent", timecontrol['percent']) eng.setoption("tcmax", reserve_max) eng.setoption("tcturns", max_moves) eng.setoption("tctotal", max_gametime) eng.setoption("tcturntime", max_turn) else: max_gametime = 0 max_moves = 0 for eng in engines: eng.newgame() if position: eng.setposition(position) eng.isready() insetup = False if not position: insetup = True position = Position(Color.GOLD, 4, board.BLANK_BOARD) starttime = time.time() if max_gametime: endtime_limit = starttime + max_gametime position.movenumber = 1 limit_winner = 1 while insetup or not position.is_end_state(): #print "%d%s" % (position.movenumber, "gs"[position.color]) #print position.board_to_str() side = position.color engine = engines[side] if timecontrol: if engine.protocol_version > 0: engine.setoption("greserve", int(reserves[0])) engine.setoption("sreserve", int(reserves[1])) else: engine.setoption("wreserve", int(reserves[0])) engine.setoption("breserve", int(reserves[1])) engine.setoption("tcmoveused", 0) movestart = time.time() engine.setoption("moveused", 0) engine.go() if timecontrol: timeout = movestart + time_incr + reserves[side] if max_turn and starttime + max_turn > timeout: timeout = starttime + max_turn if max_gametime and endtime_limit < timeout: timeout = endtime_limit bstr = position.board_to_str("short") gp = 0 for p in "EMHDCR": gp += bstr.count(p) sp = 0 for p in "emhdcr": sp += bstr.count(p) if gp > sp: limit_winner = 0 elif sp > gp: limit_winner = 1 else: timeout = None resp = None try: while not timeout or time.time() < timeout: if timeout: wait = timeout - time.time() else: wait = None resp = engine.get_response(wait) if resp.type == "bestmove": break if resp.type == "info": log.info("%s info: %s" % ("gs"[side], resp.message)) elif resp.type == "log": log.info("%s log: %s" % ("gs"[side], resp.message)) except socket.timeout: engine.stop() endtime = time.time() if resp and resp.type == "bestmove": if timecontrol: moveend = time.time() if moveend > timeout: return (side ^ 1, "t", position) if not insetup: reserve_incr = ((time_incr - (moveend - movestart)) * reserve_per) reserves[side] += reserve_incr if reserve_max: reserves[side] = min(reserves[side], reserve_max) move = resp.move mn = position.movenumber position = position.do_move_str(move) if position.color == Color.GOLD: mn += 1 position.movenumber = mn log.info("position:\n%s", position.board_to_str()) for eng in engines: eng.makemove(move) if insetup and side == Color.SILVER: insetup = False if max_moves and position.movenumber > max_moves: return (limit_winner, "s", position) elif not max_gametime or endtime < endtime_limit: return (side ^ 1, "t", position) else: # exceeded game time limit return (limit_winner, "s", position) if position.is_goal(): result = (min(position.is_goal(), 0), "g", position) elif position.is_rabbit_loss(): result = (min(position.is_rabbit_loss(), 0), "e", position) else: # immobilization assert len(position.get_steps()) == 0 result = (position.color ^ 1, "m", position) return result
class Game(object): def __init__(self, gold, silver, timecontrol=None, start_position=None, strict_setup=True, min_timeleft=None): self.engines = (gold, silver) try: self.timecontrol = timecontrol[0] self.side_tc = timecontrol except TypeError: self.timecontrol = timecontrol self.side_tc = [timecontrol, timecontrol] self.reserves = [None, None] if timecontrol: for side, eng in enumerate(self.engines): if not self.side_tc[side]: continue self.reserves[side] = self.side_tc[side].reserve eng.setoption("tcmove", self.side_tc[side].move) eng.setoption("tcreserve", self.side_tc[side].reserve) eng.setoption("tcpercent", self.side_tc[side].percent) eng.setoption("tcmax", self.side_tc[side].max_reserve) eng.setoption("tcturns", self.side_tc[side].turn_limit) eng.setoption("tctotal", self.side_tc[side].time_limit) eng.setoption("tcturntime", self.side_tc[side].max_turntime) for eng in self.engines: eng.newgame() if start_position: eng.setposition(start_position) resps = eng.isready() side = "gs"[self.engines.index(eng)] eng_name = eng.ident["name"] for response in resps: if response.type == "info": log.info("%s (%s) info: %s", eng_name, side, response.message) elif response.type == "log": log.info("%s (%s) log: %s", eng_name, side, response.message) else: log.warn( "Unexpected response while initializing %s (%s) (%s).", eng_name, side, response.type) self.insetup = False self.position = start_position if not start_position: self.insetup = True self.position = Position(Color.GOLD, 4, BLANK_BOARD) self.strict_setup = strict_setup self.min_timeleft = min_timeleft self.movenumber = 1 self.limit_winner = 1 self.moves = [] self.repetition_count = defaultdict(int) self.result = None def play(self): if self.result: raise RuntimeError("Tried to play a game that was already played.") starttime = time.time() while not self.position.is_end_state() or self.insetup: try: result = self.play_next_move(starttime) if result: break except IllegalMove as e: log.info("Illegal move played: %s" % e) result = (self.position.color ^ 1, "i") break if not result: if self.position.is_goal(): result = (0 - min(self.position.is_goal(), 0), "g") elif self.position.is_rabbit_loss(): result = (0 - min(self.position.is_rabbit_loss(), 0), "e") else: # immobilization assert len(self.position.get_steps()) == 0 result = (self.position.color ^ 1, "m") self.result = result return result def play_next_move(self, starttime): position = self.position side = position.color engine = self.engines[side] tc = self.side_tc[side] if tc: if tc.time_limit: endtime_limit = starttime + tc.time_limit if engine.protocol_version == 0: if self.reserves[0] is not None: engine.setoption("wreserve", int(self.reserves[0])) if self.reserves[1] is not None: engine.setoption("breserve", int(self.reserves[1])) engine.setoption("tcmoveused", 0) if self.reserves[0] is not None: engine.setoption("greserve", int(self.reserves[0])) if self.reserves[1] is not None: engine.setoption("sreserve", int(self.reserves[1])) engine.setoption("moveused", 0) movestart = time.time() engine.go() if tc: timeout = movestart + tc.move + self.reserves[side] if tc.max_turntime and movestart + tc.max_turntime < timeout: timeout = movestart + tc.max_turntime if tc.time_limit and endtime_limit < timeout: timeout = endtime_limit else: timeout = None waittime = None resp = None stopsent = False stoptime = None if timeout and self.min_timeleft: stoptime = timeout - self.min_timeleft while True: now = time.time() if stoptime and not stopsent and now >= stoptime: # try and get a move before time runs out engine.stop() log.info("Engine sent stop command to prevent timeout") stopsent = True if timeout and now > timeout: if not stopsent: engine.stop() break if timeout: waittime = timeout - now if stoptime and not stopsent and now + waittime > stoptime: waittime = max(0, (stoptime - now) + 0.2) try: resp = engine.get_response(waittime) if resp.type == "bestmove": break if resp.type == "info": log.info("%s (%s) info: %s", engine.ident["name"], "gs"[side], resp.message) elif resp.type == "log": log.info("%s (%s) log: %s", engine.ident["name"], "gs"[side], resp.message) except socket.timeout: pass moveend = time.time() if tc and moveend > timeout: if tc.time_limit and endtime_limit < moveend: return (self.limit_winner, "s") else: return (side ^ 1, "t") if not resp or resp.type != "bestmove": # pragma: no cover raise RuntimeError("Stopped waiting without a timeout or a move") if tc: if not self.insetup: reserve_change = tc.move - (moveend - movestart) if reserve_change > 0: # if we are adding to the reserve only apply the # percentage specified by the time control reserve_change *= tc.percent / 100.0 self.reserves[side] += reserve_change if tc.max_reserve: self.reserves[side] = min(self.reserves[side], tc.max_reserve) move = resp.move if move.lower() == "resign": return (side ^ 1, "r") self.moves.append("%d%s %s" % (self.movenumber, "gs"[position.color], move)) if self.insetup: position = position.do_move_str(move, strict_checks=self.strict_setup) else: position = position.do_move_str(move) if position.bitBoards == self.position.bitBoards: raise IllegalMove( "Tried move that did not change the position, %s" % move) self.repetition_count[position] += 1 if self.repetition_count[position] > 2: raise IllegalMove("Tried move resulting in a 3rd time repetition") self.position = position if position.color == Color.GOLD: self.movenumber += 1 log.debug("position:\n%s", position.board_to_str()) for eng in self.engines: eng.makemove(move) if self.insetup and side == Color.SILVER: self.insetup = False if not self.insetup: bstr = position.board_to_str("short") gp = 0 for p in "EMHDCR": gp += bstr.count(p) sp = 0 for p in "emhdcr": sp += bstr.count(p) if gp > sp: limit_winner = 0 elif sp > gp: limit_winner = 1 if tc and tc.turn_limit and self.movenumber > tc.turn_limit: return (limit_winner, "s")
def playgame(gold_eng, silver_eng, timecontrol=None, position=None): engines = (gold_eng, silver_eng) if timecontrol: time_incr = timecontrol['move'] reserves = [0, 0] reserves[0] = reserves[1] = timecontrol['reserve'] reserve_per = timecontrol['percent'] / 100.0 reserve_max = timecontrol['max'] max_moves = timecontrol['turns'] max_gametime = timecontrol['total'] max_turn = timecontrol['turntime'] for eng in engines: eng.setoption("tcmove", time_incr) eng.setoption("tcreserve", timecontrol['reserve']) eng.setoption("tcpercent", timecontrol['percent']) eng.setoption("tcmax", reserve_max) eng.setoption("tcturns", max_moves) eng.setoption("tctotal", max_gametime) eng.setoption("tcturntime", max_turn) else: max_gametime = 0 max_moves = 0 for eng in engines: eng.newgame() if position: eng.setposition(position) eng.isready() insetup = False if not position: insetup = True position = Position(Color.GOLD, 4, board.BLANK_BOARD) starttime = time.time() if max_gametime: endtime_limit = starttime + max_gametime position.movenumber = 1 limit_winner = 1 while insetup or not position.is_end_state(): #print "%d%s" % (position.movenumber, "gs"[position.color]) #print position.board_to_str() side = position.color engine = engines[side] if timecontrol: if engine.protocol_version > 0: engine.setoption("greserve", int(reserves[0])) engine.setoption("sreserve", int(reserves[1])) else: engine.setoption("wreserve", int(reserves[0])) engine.setoption("breserve", int(reserves[1])) engine.setoption("tcmoveused", 0) movestart = time.time() engine.setoption("moveused", 0) engine.go() if timecontrol: timeout = movestart + time_incr + reserves[side] if max_turn and starttime + max_turn > timeout: timeout = starttime + max_turn if max_gametime and endtime_limit < timeout: timeout = endtime_limit bstr = position.board_to_str("short") gp = 0 for p in "EMHDCR": gp += bstr.count(p) sp = 0 for p in "emhdcr": sp += bstr.count(p) if gp > sp: limit_winner = 0 elif sp > gp: limit_winner = 1 else: timeout = None resp = None try: while not timeout or time.time() < timeout: if timeout: wait = timeout - time.time() else: wait = None resp = engine.get_response(wait) if resp.type == "bestmove": break if resp.type == "info": log.info("%s info: %s" % ("gs"[side], resp.message)) elif resp.type == "log": log.info("%s log: %s" % ("gs"[side], resp.message)) except socket.timeout: engine.stop() endtime = time.time() if resp and resp.type == "bestmove": if timecontrol: moveend = time.time() if moveend > timeout: return (side^1, "t", position) if not insetup: reserve_incr = ((time_incr - (moveend - movestart)) * reserve_per) reserves[side] += reserve_incr if reserve_max: reserves[side] = min(reserves[side], reserve_max) move = resp.move mn = position.movenumber position = position.do_move_str(move) if position.color == Color.GOLD: mn += 1 position.movenumber = mn log.info("position:\n%s", position.board_to_str()) for eng in engines: eng.makemove(move) if insetup and side == Color.SILVER: insetup = False if max_moves and position.movenumber > max_moves: return (limit_winner, "s", position) elif not max_gametime or endtime < endtime_limit: return (side^1, "t", position) else: # exceeded game time limit return (limit_winner, "s", position) if position.is_goal(): result = (min(position.is_goal(), 0), "g", position) elif position.is_rabbit_loss(): result = (min(position.is_rabbit_loss(), 0), "e", position) else: # immobilization assert len(position.get_steps()) == 0 result = (position.color^1, "m", position) return result