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 go(self): pos = self.position if self.insetup: setup = Position(Color.GOLD, 4, BASIC_SETUP) setup_moves = setup.to_placing_move() move_str = setup_moves[pos.color][2:] else: steps, result = pos.get_rnd_step_move() move_str = pos.steps_to_str(steps) self.bestmove(move_str)
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 test_contruction(self): p = MockEngine() game = Game(p, p) self.assertEqual(game.movenumber, 1) self.assertEqual(game.insetup, True) tc = TimeControl("30s/60s") game = Game(p, p, tc) self.assertEqual(game.timecontrol, tc) pos = Position(Color.GOLD, 4, BASIC_SETUP) game = Game(p, p, tc, pos) self.assertEqual(game.position, pos) self.assertEqual(game.insetup, False)
def go(self): pos = self.position start_time = time.time() if self.insetup: setup = Position(Color.GOLD, 4, BASIC_SETUP) setup_moves = setup.to_placing_move() move_str = setup_moves[pos.color][2:] else: steps, result = pos.get_rnd_step_move() if steps is None: # we are immobilized, return an empty move move_str = "" self.log("Warning: move requested when immobilized.") else: move_str = pos.steps_to_str(steps) if self.move_delay: time.sleep(self.move_delay) move_time = time.time() - start_time self.total_move_time += move_time self.info("time %d" % (int(round(move_time), ))) self.bestmove(move_str)
def go(self): pos = self.position start_time = time.time() if self.insetup: setup = Position(Color.GOLD, 4, BASIC_SETUP) setup_moves = setup.to_placing_move() move_str = setup_moves[pos.color][2:] else: steps, result = pos.get_rnd_step_move() if steps is None: # we are immobilized, return an empty move move_str = "" self.log("Warning: move requested when immobilized.") else: move_str = pos.steps_to_str(steps) if self.move_delay: time.sleep(self.move_delay) move_time = time.time() - start_time self.total_move_time += move_time self.info("time %d" % (int(round(move_time),))) self.bestmove(move_str)
def test_contruction(self): p = MockEngine() game = Game(p, p) self.assertEqual(game.movenumber, 1) self.assertEqual(game.insetup, True) tc = TimeControl("30s/60s") game = Game(p, p, tc) self.assertEqual(game.timecontrol, tc) pos = Position(Color.GOLD, 4, BASIC_SETUP) game = Game(p, p, tc, pos) self.assertEqual(game.position, pos) self.assertEqual(game.insetup, False) real_log = pyrimaa.game.log mock_log = MockLog() pyrimaa.game.log = mock_log try: info = MockResponse("info") info.message = "Test info message." pl = MockEngine(isready=[info]) game = Game(pl, p) self.assertEqual(game.movenumber, 1) self.assertEqual(game.insetup, True) self.assertEqual(len(mock_log.info_logs), 1) self.assertEqual(len(mock_log.warn_logs), 0) self.assertIn(info.message, mock_log.info_logs[0]) mock_log.reset() log = MockResponse("log") log.message = "Test log message." pl = MockEngine(isready=[log]) game = Game(pl, p) self.assertEqual(game.movenumber, 1) self.assertEqual(game.insetup, True) self.assertEqual(len(mock_log.info_logs), 1) self.assertEqual(len(mock_log.warn_logs), 0) self.assertIn(log.message, mock_log.info_logs[0]) mock_log.reset() invalid = MockResponse("bestmove") invalid.move = " " pl = MockEngine(isready=[invalid]) game = Game(pl, p) self.assertEqual(game.movenumber, 1) self.assertEqual(game.insetup, True) self.assertEqual(len(mock_log.info_logs), 0) self.assertEqual(len(mock_log.warn_logs), 1) mock_log.reset() finally: pyrimaa.game.log = real_log
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 newgame(self): self.position = Position(Color.GOLD, 4, board.BLANK_BOARD) self.insetup = True
class AEIAdapter(object): def __init__(self, command, controller): pid = str(os.getpid()) self.posFileName = "running/matchPos" + pid self.moveFileName = "running/matchMove" + pid self.gamestateFileName = "running/matchGamestate" + pid self.command = command + " " + self.posFileName + " " + \ self.moveFileName + " " + self.gamestateFileName if not os.path.exists(os.getcwd() + "/running"): os.mkdir(os.getcwd() + "/running") self.controller = controller try: header = controller.messages.get(30) except Empty: raise Exception("Timed out waiting for AEI header") if header != "aei": raise Exception("No AEI header received, instead (%s)" % header) controller.send("protocol-version 1") controller.send("id name Adapter") controller.send("id author Rabbits") controller.send("aeiok") self.options = {} self.turnnumber = 1 self.color = Color.GOLD self.newgame() self.movesSoFar = "" def newgame(self): self.position = Position(Color.GOLD, 4, board.BLANK_BOARD) self.insetup = True def setposition(self, side_str, pos_str): side = "gswb".find(side_str) % 2 self.position = board.parse_short_pos(side, 4, pos_str) self.insetup = False def setoption(self, name, value): if name == "wreserve": name = "greserve" elif name == "breserve": name = "sreserve" elif name == "moveused": name = "tcmoveused" std_opts = set(["tcmove", "tcreserve", "tcpercent", "tcmax", "tctotal", "tcturns", "tcturntime", "greserve", "sreserve", "gused", "sused", "lastmoveused", "tcmoveused", "opponent", "opponent_rating"]) if name in std_opts: self.options[name] = int(value) else: self.log("Warning: Received unrecognized option, %s" % (name)) def makemove(self, move_str): self.position = self.position.do_move_str(move_str) movetag = str(self.turnnumber) if self.insetup and self.position.color == Color.GOLD: self.insetup = False if self.color == Color.SILVER: self.turnnumber += 1 self.color = Color.GOLD movetag += "b " # s else: self.color = Color.SILVER movetag += "w " # g self.movesSoFar += movetag + move_str + "\n" def go(self): self.writeRunningFiles() (status, move_str) = commands.getstatusoutput(self.command) # This assumes that the last (or only) line of output is the move choice move_lines = move_str.split("\n") self.bestmove(move_lines.pop()) def log(self, msg): self.controller.send("log " + msg) def bestmove(self, move_str): self.controller.send("bestmove " + move_str) def main(self): ctl = self.controller while not ctl.stop.isSet(): msg = ctl.messages.get() if msg == "isready": ctl.send("readyok") elif msg == "newgame": self.newgame() elif msg.startswith("setposition"): side, pos_str = msg.split(None, 2)[1:] self.setposition(side, pos_str) elif msg.startswith("setoption"): words = msg.split() name = words[2] v_ix = msg.find(name) + len(name) v_ix = msg.find("value", v_ix) if v_ix != -1: value = msg[v_ix + 5:] else: value = None self.setoption(name, value) elif msg.startswith("makemove"): move_str = msg.split(None, 1)[1] self.makemove(move_str) elif msg.startswith("go"): if len(msg.split()) == 1: self.go() elif msg == "stop": pass elif msg == "quit": self.removeRunningFiles() return def writeRunningFiles(self): posFile = open(self.posFileName, "w") posFile.write(self.positionString()) posFile.close() moveFile = open(self.moveFileName, "w") moveFile.write(self.moveListString()) moveFile.close() gamestateFile = open(self.gamestateFileName, "w") gamestateFile.write(self.gamestateString()) gamestateFile.close() def positionString(self): turn = str(self.turnnumber) if self.color == Color.GOLD: turn += "w" # g else: turn += "b" # s board_str = self.position.board_to_str(dots=False) # Fairy needs big X's. board_str = board_str.replace("x", "X") return turn + "\n" + board_str def moveListString(self): string = self.movesSoFar string += str(self.turnnumber) if self.color == Color.GOLD: string += "w" # g else: string += "b" # s return string + "\n" def gamestateString(self): gamestate = "" for k, v in self.options.iteritems(): if k == "greserve": key = "tcwreserve" elif k == "sreserve": key = "tcbreserve" else: key = k gamestate += k + "=" + str(v) + "\n" if self.color == Color.GOLD: gamestate += "turn=w\n" else: gamestate += "turn=b\n" gamestate += "--END--" return gamestate def removeRunningFiles(self): os.remove(self.posFileName) os.remove(self.moveFileName) os.remove(self.gamestateFileName)
def newgame(self): self.position = Position(Color.GOLD, 4, BLANK_BOARD) self.insetup = True
class AEIEngine(object): def __init__(self, controller): self.strict_checks = True self.move_delay = None self.total_move_time = 0.0 self.controller = controller try: header = controller.messages.get(30) except Empty: raise AEIException("Timed out waiting for aei header") if header != "aei": raise AEIException("Did not receive aei header, instead (%s)" % (header)) controller.send("protocol-version 1") controller.send("id name Sample Engine") controller.send("id author Janzert") controller.send("aeiok") self.newgame() def newgame(self): self.position = Position(Color.GOLD, 4, BLANK_BOARD) self.insetup = True def setposition(self, side_str, pos_str): side = "gswb".find(side_str) % 2 self.position = parse_short_pos(side, 4, pos_str) self.insetup = False def setoption(self, name, value): std_opts = set([ "tcmove", "tcreserve", "tcpercent", "tcmax", "tctotal", "tcturns", "tcturntime", "greserve", "sreserve", "gused", "sused", "lastmoveused", "moveused", "opponent", "opponent_rating" ]) if name == "checkmoves": self.strict_checks = value.lower().strip() not in [ "false", "no", "0" ] elif name == "delaymove": self.move_delay = float(value) elif name not in std_opts: self.log("Warning: Received unrecognized option, %s" % (name)) def makemove(self, move_str): try: self.position = self.position.do_move_str(move_str, self.strict_checks) except IllegalMove as exc: self.log("Error: received illegal move %s" % (move_str, )) return False if self.insetup and self.position.color == Color.GOLD: self.insetup = False return True def go(self): pos = self.position start_time = time.time() if self.insetup: setup = Position(Color.GOLD, 4, BASIC_SETUP) setup_moves = setup.to_placing_move() move_str = setup_moves[pos.color][2:] else: steps, result = pos.get_rnd_step_move() if steps is None: # we are immobilized, return an empty move move_str = "" self.log("Warning: move requested when immobilized.") else: move_str = pos.steps_to_str(steps) if self.move_delay: time.sleep(self.move_delay) move_time = time.time() - start_time self.total_move_time += move_time self.info("time %d" % (int(round(move_time), ))) self.bestmove(move_str) def info(self, msg): self.controller.send("info " + msg) def log(self, msg): self.controller.send("log " + msg) def bestmove(self, move_str): self.controller.send("bestmove " + move_str) def main(self): ctl = self.controller while not ctl.stop.isSet(): msg = ctl.messages.get() if msg == "isready": ctl.send("readyok") elif msg == "newgame": self.newgame() elif msg.startswith("setposition"): side, pos_str = msg.split(None, 2)[1:] self.setposition(side, pos_str) elif msg.startswith("setoption"): words = msg.split() name = words[2] v_ix = msg.find(name) + len(name) v_ix = msg.find("value", v_ix) if v_ix != -1: value = msg[v_ix + 5:] else: value = None self.setoption(name, value) elif msg.startswith("makemove"): move_str = msg.split(None, 1)[1] if not self.makemove(move_str): return elif msg.startswith("go"): if len(msg.split()) == 1: self.go() elif msg == "stop": pass elif msg == "quit": self.log("Debug: Exiting after receiving quit message.") if self.total_move_time > 0: self.info("move gen time %f" % (self.total_move_time, )) return
class AEIEngine(object): def __init__(self, controller): self.strict_checks = True self.move_delay = None self.total_move_time = 0.0 self.controller = controller try: header = controller.messages.get(30) except Empty: raise AEIException("Timed out waiting for aei header") if header != "aei": raise AEIException("Did not receive aei header, instead (%s)" % (header)) controller.send("protocol-version 1") controller.send("id name Sample Engine") controller.send("id author Janzert") controller.send("aeiok") self.newgame() def newgame(self): self.position = Position(Color.GOLD, 4, BLANK_BOARD) self.insetup = True def setposition(self, side_str, pos_str): side = "gswb".find(side_str) % 2 self.position = parse_short_pos(side, 4, pos_str) self.insetup = False def setoption(self, name, value): std_opts = set(["tcmove", "tcreserve", "tcpercent", "tcmax", "tctotal", "tcturns", "tcturntime", "greserve", "sreserve", "gused", "sused", "lastmoveused", "moveused", "opponent", "opponent_rating"]) if name == "checkmoves": self.strict_checks = value.lower() in ["false", "no", "0"] elif name == "delaymove": self.move_delay = float(value) elif name not in std_opts: self.log("Warning: Received unrecognized option, %s" % (name)) def makemove(self, move_str): try: self.position = self.position.do_move_str(move_str, self.strict_checks) except IllegalMove as exc: self.log("Error: received illegal move %s" % (move_str,)) return False if self.insetup and self.position.color == Color.GOLD: self.insetup = False return True def go(self): pos = self.position start_time = time.time() if self.insetup: setup = Position(Color.GOLD, 4, BASIC_SETUP) setup_moves = setup.to_placing_move() move_str = setup_moves[pos.color][2:] else: steps, result = pos.get_rnd_step_move() if steps is None: # we are immobilized, return an empty move move_str = "" self.log("Warning: move requested when immobilized.") else: move_str = pos.steps_to_str(steps) if self.move_delay: time.sleep(self.move_delay) move_time = time.time() - start_time self.total_move_time += move_time self.info("time %d" % (int(round(move_time),))) self.bestmove(move_str) def info(self, msg): self.controller.send("info " + msg) def log(self, msg): self.controller.send("log " + msg) def bestmove(self, move_str): self.controller.send("bestmove " + move_str) def main(self): ctl = self.controller while not ctl.stop.isSet(): msg = ctl.messages.get() if msg == "isready": ctl.send("readyok") elif msg == "newgame": self.newgame() elif msg.startswith("setposition"): side, pos_str = msg.split(None, 2)[1:] self.setposition(side, pos_str) elif msg.startswith("setoption"): words = msg.split() name = words[2] v_ix = msg.find(name) + len(name) v_ix = msg.find("value", v_ix) if v_ix != -1: value = msg[v_ix + 5:] else: value = None self.setoption(name, value) elif msg.startswith("makemove"): move_str = msg.split(None, 1)[1] if not self.makemove(move_str): return elif msg.startswith("go"): if len(msg.split()) == 1: self.go() elif msg == "stop": pass elif msg == "quit": self.log("Debug: Exiting after receiving quit message.") if self.total_move_time > 0: self.info("move gen time %f" % (self.total_move_time,)) return
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 AEIEngine(object): def __init__(self, controller): self.controller = controller try: header = controller.messages.get(30) except Empty: raise AEIException("Timed out waiting for aei header") if header != "aei": raise AEIException("Did not receive aei header, instead (%s)" % ( header)) controller.send("protocol-version 1") controller.send("id name Sample Engine") controller.send("id author Janzert") controller.send("aeiok") self.newgame() def newgame(self): self.position = Position(Color.GOLD, 4, BLANK_BOARD) self.insetup = True def setposition(self, side_str, pos_str): side = "gswb".find(side_str) % 2 self.position = parse_short_pos(side, 4, pos_str) self.insetup = False def setoption(self, name, value): std_opts = set(["tcmove", "tcreserve", "tcpercent", "tcmax", "tctotal", "tcturns", "tcturntime", "greserve", "sreserve", "gused", "sused", "lastmoveused", "moveused", "opponent", "opponent_rating"]) if name not in std_opts: self.log("Warning: Received unrecognized option, %s" % (name)) def makemove(self, move_str): self.position = self.position.do_move_str(move_str) if self.insetup and self.position.color == Color.GOLD: self.insetup = False def go(self): pos = self.position if self.insetup: setup = Position(Color.GOLD, 4, BASIC_SETUP) setup_moves = setup.to_placing_move() move_str = setup_moves[pos.color][2:] else: steps, result = pos.get_rnd_step_move() move_str = pos.steps_to_str(steps) self.bestmove(move_str) def log(self, msg): self.controller.send("log " + msg) def bestmove(self, move_str): self.controller.send("bestmove " + move_str) def main(self): ctl = self.controller while not ctl.stop.isSet(): msg = ctl.messages.get() if msg == "isready": ctl.send("readyok") elif msg == "newgame": self.newgame() elif msg.startswith("setposition"): side, pos_str = msg.split(None, 2)[1:] self.setposition(side, pos_str) elif msg.startswith("setoption"): words = msg.split() name = words[2] v_ix = msg.find(name) + len(name) v_ix = msg.find("value", v_ix) if v_ix != -1: value = msg[v_ix + 5:] else: value = None self.setoption(name, value) elif msg.startswith("makemove"): move_str = msg.split(None, 1)[1] self.makemove(move_str) elif msg.startswith("go"): if len(msg.split()) == 1: self.go() elif msg == "stop": pass elif msg == "quit": return
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")
class AEIAdapter(object): def __init__(self, command, controller): pid = str(os.getpid()) self.posFileName = "running/matchPos" + pid self.moveFileName = "running/matchMove" + pid self.gamestateFileName = "running/matchGamestate" + pid self.command = command + " " + self.posFileName + " " + \ self.moveFileName + " " + self.gamestateFileName if not os.path.exists(os.getcwd() + "/running"): os.mkdir(os.getcwd() + "/running") self.controller = controller try: header = controller.messages.get(30) except Empty: raise Exception("Timed out waiting for AEI header") if header != "aei": raise Exception("No AEI header received, instead (%s)" % header) controller.send("protocol-version 1") controller.send("id name Adapter") controller.send("id author Rabbits") controller.send("aeiok") self.options = {} self.turnnumber = 1 self.color = Color.GOLD self.newgame() self.movesSoFar = "" def newgame(self): self.position = Position(Color.GOLD, 4, board.BLANK_BOARD) self.insetup = True def setposition(self, side_str, pos_str): side = "gswb".find(side_str) % 2 self.position = board.parse_short_pos(side, 4, pos_str) self.insetup = False def setoption(self, name, value): if name == "wreserve": name = "greserve" elif name == "breserve": name = "sreserve" elif name == "moveused": name = "tcmoveused" std_opts = set([ "tcmove", "tcreserve", "tcpercent", "tcmax", "tctotal", "tcturns", "tcturntime", "greserve", "sreserve", "gused", "sused", "lastmoveused", "tcmoveused", "opponent", "opponent_rating" ]) if name in std_opts: self.options[name] = int(value) else: self.log("Warning: Received unrecognized option, %s" % (name)) def makemove(self, move_str): self.position = self.position.do_move_str(move_str) movetag = str(self.turnnumber) if self.insetup and self.position.color == Color.GOLD: self.insetup = False if self.color == Color.SILVER: self.turnnumber += 1 self.color = Color.GOLD movetag += "b " # s else: self.color = Color.SILVER movetag += "w " # g self.movesSoFar += movetag + move_str + "\n" def go(self): self.writeRunningFiles() (status, move_str) = commands.getstatusoutput(self.command) # This assumes that the last (or only) line of output is the move choice move_lines = move_str.split("\n") self.bestmove(move_lines.pop()) def log(self, msg): self.controller.send("log " + msg) def bestmove(self, move_str): self.controller.send("bestmove " + move_str) def main(self): ctl = self.controller while not ctl.stop.isSet(): msg = ctl.messages.get() if msg == "isready": ctl.send("readyok") elif msg == "newgame": self.newgame() elif msg.startswith("setposition"): side, pos_str = msg.split(None, 2)[1:] self.setposition(side, pos_str) elif msg.startswith("setoption"): words = msg.split() name = words[2] v_ix = msg.find(name) + len(name) v_ix = msg.find("value", v_ix) if v_ix != -1: value = msg[v_ix + 5:] else: value = None self.setoption(name, value) elif msg.startswith("makemove"): move_str = msg.split(None, 1)[1] self.makemove(move_str) elif msg.startswith("go"): if len(msg.split()) == 1: self.go() elif msg == "stop": pass elif msg == "quit": self.removeRunningFiles() return def writeRunningFiles(self): posFile = open(self.posFileName, "w") posFile.write(self.positionString()) posFile.close() moveFile = open(self.moveFileName, "w") moveFile.write(self.moveListString()) moveFile.close() gamestateFile = open(self.gamestateFileName, "w") gamestateFile.write(self.gamestateString()) gamestateFile.close() def positionString(self): turn = str(self.turnnumber) if self.color == Color.GOLD: turn += "w" # g else: turn += "b" # s board_str = self.position.board_to_str(dots=False) # Fairy needs big X's. board_str = board_str.replace("x", "X") return turn + "\n" + board_str def moveListString(self): string = self.movesSoFar string += str(self.turnnumber) if self.color == Color.GOLD: string += "w" # g else: string += "b" # s return string + "\n" def gamestateString(self): gamestate = "" for k, v in self.options.iteritems(): if k == "greserve": key = "tcwreserve" elif k == "sreserve": key = "tcbreserve" else: key = k gamestate += k + "=" + str(v) + "\n" if self.color == Color.GOLD: gamestate += "turn=w\n" else: gamestate += "turn=b\n" gamestate += "--END--" return gamestate def removeRunningFiles(self): os.remove(self.posFileName) os.remove(self.moveFileName) os.remove(self.gamestateFileName)
class AEIEngine(object): def __init__(self, controller): self.controller = controller try: header = controller.messages.get(30) except Empty: raise AEIException("Timed out waiting for aei header") if header != "aei": raise AEIException("Did not receive aei header, instead (%s)" % (header)) controller.send("protocol-version 1") controller.send("id name Sample Engine") controller.send("id author Janzert") controller.send("aeiok") self.newgame() def newgame(self): self.position = Position(Color.GOLD, 4, BLANK_BOARD) self.insetup = True def setposition(self, side_str, pos_str): side = "gswb".find(side_str) % 2 self.position = parse_short_pos(side, 4, pos_str) self.insetup = False def setoption(self, name, value): std_opts = set(["tcmove", "tcreserve", "tcpercent", "tcmax", "tctotal", "tcturns", "tcturntime", "greserve", "sreserve", "gused", "sused", "lastmoveused", "moveused", "opponent", "opponent_rating"]) if name not in std_opts: self.log("Warning: Received unrecognized option, %s" % (name)) def makemove(self, move_str): self.position = self.position.do_move_str(move_str) if self.insetup and self.position.color == Color.GOLD: self.insetup = False def go(self): pos = self.position if self.insetup: setup = Position(Color.GOLD, 4, BASIC_SETUP) setup_moves = setup.to_placing_move() move_str = setup_moves[pos.color][2:] else: steps, result = pos.get_rnd_step_move() move_str = pos.steps_to_str(steps) self.bestmove(move_str) def log(self, msg): self.controller.send("log " + msg) def bestmove(self, move_str): self.controller.send("bestmove " + move_str) def main(self): ctl = self.controller while not ctl.stop.isSet(): msg = ctl.messages.get() if msg == "isready": ctl.send("readyok") elif msg == "newgame": self.newgame() elif msg.startswith("setposition"): side, pos_str = msg.split(None, 2)[1:] self.setposition(side, pos_str) elif msg.startswith("setoption"): words = msg.split() name = words[2] v_ix = msg.find(name) + len(name) v_ix = msg.find("value", v_ix) if v_ix != -1: value = msg[v_ix + 5:] else: value = None self.setoption(name, value) elif msg.startswith("makemove"): move_str = msg.split(None, 1)[1] self.makemove(move_str) elif msg.startswith("go"): if len(msg.split()) == 1: self.go() elif msg == "stop": pass elif msg == "quit": return