def score_planet(pw: planet_wars.PlanetWars, p: planet_wars.Planet): """ Function to give a planet a score based on many factors. :param pw: `PlanetWars` object :param p: `Planet` object :return: `float` score of planet """ raw_score = get_raw_score(p) structural_score = 1 - (pythag(MY_PLANETS_CENTER, (p.x(), p.y())) / pw.map_size) surrounding_score = 0 for planet in filter(lambda _p: _p != p, pw.planets()): temp = ( 1 - (pw.distance(p.planet_id(), planet.planet_id()) / pw.map_size))**5 surrounding_score += get_raw_score(planet) * temp surrounding_score /= pw.total_growth latency_score = p.latency / pw.map_size center_score = 1 - (pw.distance(p.planet_id(), 0) / pw.map_size) score = 0 score += raw_score score += STRUCTURAL_FACTOR * structural_score score += SURROUNDING_FACTOR * surrounding_score score += LATENCY_FACTOR * latency_score score += CENTER_FACTOR * center_score return score
def get_info(pw: planet_wars.PlanetWars): """ Gets basic info about the map. Saves everything in global variables. :param pw: `PlanetWars` object :return: None """ # get the euclidean center of my and enemy's planets global MY_PLANETS_CENTER, ENEMY_PLANETS_CENTER MY_PLANETS_CENTER = sum(map(lambda p: p.x(), pw.my_planets())) / len(pw.my_planets()), \ sum(map(lambda p: p.y(), pw.my_planets())) / len(pw.my_planets()) ENEMY_PLANETS_CENTER = sum(map(lambda p: p.x(), pw.enemy_planets())) / len(pw.enemy_planets()), \ sum(map(lambda p: p.y(), pw.enemy_planets())) / len(pw.enemy_planets())
def furthest_meaningful_planet(pw: planet_wars.PlanetWars, planet: planet_wars.Planet, owner: int): planets = tuple(filter(lambda p: p.owner() == owner, pw.planets())) fleets = tuple(filter(lambda f: f.owner() == owner, pw.fleets())) furthest_distance = 0 for other_planet in planets: furthest_distance = max( furthest_distance, pw.distance(other_planet.planet_id(), planet.planet_id())) for fleet in fleets: furthest_distance = max( furthest_distance, fleet.turns_remaining() + pw.distance(fleet.destination_planet(), planet.planet_id())) return furthest_distance
def __init__(self, **kwargs): # rip out the game settings we want players = kwargs.pop('players') gamestate = kwargs.pop('gamestate') self.game = PlanetWars(gamestate) for p in players: self.game.add_player(p) self.max_tick = kwargs.pop('max_game_length') self.max_tick += self.max_tick / 2 # set and use pyglet window settings kwargs.update({ 'width': 500, 'height': 500, 'vsync': True, 'resizable': False, }) super(PlanetWarsWindow, self).__init__(**kwargs) # create a pyglet window and set glOptions glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glClearColor(0., 0., 0., 1.0) # Grey # current "pen" colour of lines self.pen_color = (1, 0, 0, 1.) self.stroke = 1.0 # - thickness default self.qobj = gluNewQuadric() # gluQuadricDrawStyle(self.qobj, GLU_FILL) #GLU_SILHOUETTE) # prep the fps display and some labels self.fps_display = clock.ClockDisplay() clWhite = (255, 255, 255, 255) self.step_label = Label('STEP', x=5, y=self.height - 20, color=clWhite) self.fps = 0 self.set_fps(20) self.paused = True self.view_id = 0 self.label_type = 'num_ships' # create adaptor to help with drawing self.adaptor = PlanetWarsScreenAdapter(self.game, self.circle) # prep the game (space!) self.reset_space() # add extra event handlers we need self.add_handlers()
class PlanetTest(unittest.TestCase): def setUp(self): self.pw = PlanetWars() def _game_over_true(self, max_turn): try: self.pw.is_game_over(max_turn) self.fail("Exception expected") except EndOfTheGame: pass def _game_over_false(self, max_turn): try: self.pw.is_game_over(max_turn) except EndOfTheGame: self.fail("Exception unexpected") def test_is_game_over(self): self.pw.turn = 10 self._game_over_true(9) self.pw.turn = 1 self._game_over_true(1) self.pw.planets.append(Planet(1,1,10,5,10,10)) self._game_over_true(1) self.pw.planets.append(Planet(2,2,10,5,10,10)) self._game_over_false(1) self.pw.planets = [] self._game_over_true(1) self.pw.fleets.append(Fleet(1, 10, 1, 2, 10, 10)) self._game_over_true(1) self.pw.fleets.append(Fleet(2, 10, 1, 2, 10, 10)) self._game_over_false(1) def test_pov(self): self.assertEqual(1, pov(1,1)) self.assertEqual(2, pov(2,1)) self.assertEqual(1, pov(2,2)) self.assertEqual(2, pov(1,2)) self.assertEqual(0, pov(0,1)) self.assertEqual(0, pov(0,2))
class PlanetTest(unittest.TestCase): def setUp(self): self.pw = PlanetWars() def _game_over_true(self, max_turn): try: self.pw.is_game_over(max_turn) self.fail("Exception expected") except EndOfTheGame: pass def _game_over_false(self, max_turn): try: self.pw.is_game_over(max_turn) except EndOfTheGame: self.fail("Exception unexpected") def test_is_game_over(self): self.pw.turn = 10 self._game_over_true(9) self.pw.turn = 1 self._game_over_true(1) self.pw.planets.append(Planet(1, 1, 10, 5, 10, 10)) self._game_over_true(1) self.pw.planets.append(Planet(2, 2, 10, 5, 10, 10)) self._game_over_false(1) self.pw.planets = [] self._game_over_true(1) self.pw.fleets.append(Fleet(1, 10, 1, 2, 10, 10)) self._game_over_true(1) self.pw.fleets.append(Fleet(2, 10, 1, 2, 10, 10)) self._game_over_false(1) def test_pov(self): self.assertEqual(1, pov(1, 1)) self.assertEqual(2, pov(2, 1)) self.assertEqual(1, pov(2, 2)) self.assertEqual(2, pov(1, 2)) self.assertEqual(0, pov(0, 1)) self.assertEqual(0, pov(0, 2))
def __init__(self, mapp, enemy_cmd, my_bot_class, timeout=1000, max_turns=200): super(Engine, self).__init__() self.mapp = mapp self.timeout = timeout self.max_turns = max_turns self.enemy_cmd = enemy_cmd self.pw = PlanetWars() try: self.my_bot = my_bot_class() except: self.my_bot = None self.debug_name = "engine" self.playback = ""
def defensible(pw: planet_wars.PlanetWars, planet: planet_wars.Planet): quickest_planet = min(pw.my_planets(), key=lambda p: turn_to_take(pw, p, planet)) quickest_turns = turn_to_take(pw, quickest_planet, planet) for t in range(quickest_turns + 1, furthest_meaningful_planet(pw, planet, 2) + 2): my_maximum_ships = max( 0, sum(planet.my_maximum_ships[:t - 1]) - planet.num_ships() + planet.growth_rate() * (t - quickest_turns)) enemy_maximum_ships = sum(planet.enemy_maximum_ships[:t]) if my_maximum_ships < enemy_maximum_ships: return False return True
def __init__(self, **kwargs): # rip out the game settings we want players = kwargs.pop('players') gamestate = kwargs.pop('gamestate') self.game = PlanetWars(gamestate) for p in players: self.game.add_player(p) self.max_tick = kwargs.pop('max_game_length') # set and use pyglet window settings kwargs.update({ 'width': 500, 'height': 500, 'vsync': True, 'resizable': False, }) super(PlanetWarsWindow, self).__init__(**kwargs) # create a pyglet window and set glOptions glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glClearColor(0., 0., 0., 1.0) # Grey # current "pen" colour of lines self.pen_color = (1, 0, 0, 1.) self.stroke = 1.0 # - thickness default self.qobj = gluNewQuadric() # gluQuadricDrawStyle(self.qobj, GLU_FILL) #GLU_SILHOUETTE) # prep the fps display and some labels self.fps_display = clock.ClockDisplay() clWhite = (255, 255, 255, 255) self.step_label = Label('STEP', x=5, y=self.height - 20, color=clWhite) self.fps = 0 self.set_fps(20) self.paused = True self.view_id = 0 self.label_type = 'num_ships' # create adaptor to help with drawing self.adaptor = PlanetWarsScreenAdapter(self.game, self.circle) # prep the game (space!) self.reset_space() # add extra event handlers we need self.add_handlers()
def turn_to_take(pw: planet_wars.PlanetWars, my_planet: planet_wars.Planet, neutral_planet: planet_wars.Planet): """ Finds the minimum turns to take `neutral_planet` with `my_planet`. :param pw: `PlanetWars` object :param my_planet: `Planet` object :param neutral_planet: `Planet` object :return: `int` turns to take the planet """ distance = pw.distance(my_planet.planet_id(), neutral_planet.planet_id()) if my_planet.num_ships() > neutral_planet.num_ships(): return distance else: lacking_ships = neutral_planet.num_ships() - my_planet.num_ships() + 1 for t in range(pw.map_size): lacking_ships -= my_planet.my_arriving_ships[ t] + my_planet.growth_rate() if lacking_ships <= 0: break else: return 999999 return distance + t
def setUp(self): self.pw = PlanetWars()
def load_init_state(self): '''load map data and make initial game state''' self.pw = PlanetWars() self.pw.load_data(self.load_map_data()) self.playback = ":".join(["%.10f,%.10f,%d,%d,%d" % (p.x, p.y, p.owner, p.num_ships, p.growth_rate) for p in self.pw.planets]) + "|"
def expand(pw: planet_wars.PlanetWars, expand_limit: int = 99, possible_planets=None, reckless: bool = False): """ Expand to neutral planets with all ships. Designed to come after `defend_possible()` because this doesn't account for possible attacks from the opponent. :param pw: `PlanetWars` object :param expand_limit: `int` the maximum number of planets to expand to. :param possible_planets: `list` of `Planet` objects, the planets to consider expanding to. None -> all :param reckless: `bool` whether to care about the defensibility of the planet :return: None """ expand_limit = min(expand_limit, len(pw.neutral_planets())) if possible_planets is None: possible_planets = filter(lambda p: p not in pw.my_future_neutrals, pw.neutral_planets()) possible_planets = filter(lambda p: p not in pw.enemy_future_neutrals, possible_planets) sorted_planets = sorted( possible_planets, key=lambda p: (score_planet(pw, p) - get_raw_score(p) + return_ships(pw, p) / (pw.map_size / 2)) / (p.num_ships() + 1), reverse=True) for _ in range(expand_limit): for attack_planet in sorted_planets[:expand_limit]: if not (attack_planet.latency > 0 and attack_planet.num_ships() < attack_planet.growth_rate()) and \ not reckless and not defensible(pw, attack_planet): continue # if not reckless and not defensible(pw, attack_planet): # continue quickest_planet = min( pw.my_planets(), key=lambda p: turn_to_take(pw, p, attack_planet)) closest_distance = pw.map_size for enemy_planet in pw.enemy_planets(): closest_distance = min( closest_distance, pw.distance(enemy_planet.planet_id(), attack_planet.planet_id())) for enemy_planet in pw.enemy_future_neutrals: closest_distance = min( closest_distance, pw.distance(enemy_planet.planet_id(), attack_planet.planet_id()) + pw.enemy_future_neutrals[enemy_planet][0]) if turn_to_take(pw, quickest_planet, attack_planet) > closest_distance: continue if quickest_planet.num_ships() > attack_planet.num_ships(): pw.issue_order(quickest_planet.planet_id(), attack_planet.planet_id(), attack_planet.num_ships() + 1) quickest_planet.remove_ships(attack_planet.num_ships() + 1) pw.my_future_neutrals[attack_planet] = (pw.distance( quickest_planet.planet_id(), attack_planet.planet_id()), 1) for planet in pw.planets(): planet.my_maximum_ships[pw.distance(quickest_planet.planet_id(), planet.planet_id()) - 1] -= \ attack_planet.num_ships() planet.my_maximum_ships[ pw.distance(quickest_planet.planet_id(), attack_planet.planet_id()) + pw.distance(attack_planet.planet_id(), planet.planet_id())] += 1 for t in range( pw.distance(quickest_planet.planet_id(), attack_planet.planet_id()) + pw.distance(attack_planet.planet_id(), planet.planet_id()), 2 * pw.map_size): planet.my_maximum_ships[ t] += attack_planet.growth_rate() expand_limit -= 1 sorted_planets.remove(attack_planet) break else: quickest_planet.num_ships(0) return else: break
def return_ships(pw: planet_wars.PlanetWars, planet: planet_wars.Planet): quickest_planet = min(pw.my_planets(), key=lambda p: turn_to_take(pw, p, planet)) quickest_turns = turn_to_take(pw, quickest_planet, planet) return planet.growth_rate() * (pw.map_size / 2 - quickest_turns)
class PlanetWarsWindow(window.Window): def __init__(self, **kwargs): # rip out the game settings we want players = kwargs.pop('players') gamestate = kwargs.pop('gamestate') self.game = PlanetWars(gamestate) for p in players: self.game.add_player(p) self.max_tick = kwargs.pop('max_game_length') # set and use pyglet window settings kwargs.update({ 'width': 500, 'height': 500, 'vsync': True, 'resizable': False, }) super(PlanetWarsWindow, self).__init__(**kwargs) # create a pyglet window and set glOptions glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glClearColor(0., 0., 0., 1.0) # Grey # current "pen" colour of lines self.pen_color = (1, 0, 0, 1.) self.stroke = 1.0 # - thickness default self.qobj = gluNewQuadric() # gluQuadricDrawStyle(self.qobj, GLU_FILL) #GLU_SILHOUETTE) # prep the fps display and some labels self.fps_display = clock.ClockDisplay() clWhite = (255, 255, 255, 255) self.step_label = Label('STEP', x=5, y=self.height - 20, color=clWhite) self.fps = 0 self.set_fps(20) self.paused = True self.view_id = 0 self.label_type = 'num_ships' # create adaptor to help with drawing self.adaptor = PlanetWarsScreenAdapter(self.game, self.circle) # prep the game (space!) self.reset_space() # add extra event handlers we need self.add_handlers() def reset_space(self): self.adaptor.screen_resize(self.width, self.height) self.adaptor.sync_all(self.view_id, self.label_type) def set_fps(self, fps): self.fps = max(fps, 5) clock.unschedule(self.update) clock.schedule_interval(self.update, 1.0 / self.fps) def update(self, args): # gets called by the scheduler at the step_fps interval set game = self.game if game: if not self.paused: game.update() self.adaptor.sync_all() # update step label msg = 'Step:' + str(game.tick) if self.paused: msg += ' [PAUSED]' msg += ', View:' + str(self.view_id) if self.view_id in game.players: msg += ' ' + game.players[self.view_id].name elif self.view_id == 0: msg += ' All ' msg += str(game.tick) msg += ' Show: ' + self.label_type self.step_label.text = msg # Has the game ended? (Should we close?) if not self.game.is_alive() or self.game.tick >= self.max_tick: self.close() else: self.step_label.text = "---" def add_handlers(self): @self.event def on_resize(cx, cy): self.adaptor.screen_resize(cx, cy) pass @self.event def on_mouse_press(x, y, button, modifiers): pass @self.event def on_key_press(symbol, modifiers): # Single Player View, or All View if symbol == key.BRACKETLEFT: self.view_id = self.view_id - 1 if self.view_id > 1 else len( self.game.players) if symbol == key.BRACKETRIGHT: self.view_id = self.view_id + 1 if self.view_id < len( self.game.players) else 1 # Everyone view elif symbol == key.A: self.view_id = 0 # == "all" # Planet attribute type to show? elif symbol == key.L: i = self.label_type l = ['id', 'num_ships', 'vision_age', 'owner_id'] self.label_type = l[l.index(i) + 1] if l.index(i) < (len(l) - 1) else l[0] # Reset? elif symbol == key.R: self.reset_space() # Do one step elif symbol == key.N: self.game.update() # Pause toggle? elif symbol == key.P: self.paused = not self.paused # Speed up (+) or slow down (-) the sim elif symbol in [key.PLUS, key.EQUAL]: self.set_fps(self.fps + 5) elif symbol == key.MINUS: self.set_fps(self.fps - 5) self.adaptor.sync_all(self.view_id, self.label_type) @self.event def on_draw(): self.clear() self.fps_display.draw() self.step_label.draw() self.adaptor.draw() def set_pen_color(self, color=None, name=None): if name is not None: color = COLOR_NAMES[name] self.curr_color = color glColor4f(*self.curr_color) def set_stroke(self, stroke): self.stroke = stroke glLineWidth(self.stroke) def circle(self, pos, radius, color=None, filled=True): if color: self.set_pen_color(color) if filled: gluQuadricDrawStyle(self.qobj, GLU_FILL) else: gluQuadricDrawStyle(self.qobj, GLU_SILHOUETTE) glPushMatrix() glTranslatef(pos[0], pos[1], 0.0) gluDisk(self.qobj, 0, radius, 32, 1) glPopMatrix() def line(self, x1=0, y1=0, x2=0, y2=0, pos1=None, pos2=None): ''' Draw a single line. Either with xy values, or two position (that contain x and y values). Uses existing colour and stroke values. ''' if pos1 is not None and pos2 is not None: x1, y1, x2, y2 = pos1[0], pos1[1], pos2[0], pos2[1] glBegin(GL_LINES) glVertex2f(x1, y1) glVertex2f(x2, y2) glEnd()
class PlanetWarsWindow(window.Window): def __init__(self, **kwargs): # rip out the game settings we want players = kwargs.pop('players') gamestate = kwargs.pop('gamestate') self.game = PlanetWars(gamestate) for p in players: self.game.add_player(p) self.max_tick = kwargs.pop('max_game_length') # set and use pyglet window settings kwargs.update({ 'width': 500, 'height': 500, 'vsync': True, 'resizable': False, }) super(PlanetWarsWindow, self).__init__(**kwargs) # create a pyglet window and set glOptions glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glClearColor(0., 0., 0., 1.0) # Grey # current "pen" colour of lines self.pen_color = (1, 0, 0, 1.) self.stroke = 1.0 # - thickness default self.qobj = gluNewQuadric() # gluQuadricDrawStyle(self.qobj, GLU_FILL) #GLU_SILHOUETTE) # prep the fps display and some labels self.fps_display = clock.ClockDisplay() clWhite = (255, 255, 255, 255) self.step_label = Label('STEP', x=5, y=self.height - 20, color=clWhite) self.fps = 0 self.set_fps(20) self.paused = True self.view_id = 0 self.label_type = 'num_ships' # create adaptor to help with drawing self.adaptor = PlanetWarsScreenAdapter(self.game, self.circle) # prep the game (space!) self.reset_space() # add extra event handlers we need self.add_handlers() def reset_space(self): self.adaptor.screen_resize(self.width, self.height) self.adaptor.sync_all(self.view_id, self.label_type) def set_fps(self, fps): self.fps = max(fps, 5) clock.unschedule(self.update) clock.schedule_interval(self.update, 1.0 / self.fps) def update(self, args): # gets called by the scheduler at the step_fps interval set game = self.game if game: if not self.paused: game.update() self.adaptor.sync_all() # update step label msg = 'Step:' + str(game.tick) if self.paused: msg += ' [PAUSED]' msg += ', View:' + str(self.view_id) if self.view_id in game.players: msg += ' ' + game.players[self.view_id].name elif self.view_id == 0: msg += ' All ' msg += str(game.tick) msg += ' Show: ' + self.label_type self.step_label.text = msg # Has the game ended? (Should we close?) if not self.game.is_alive() or self.game.tick >= self.max_tick: self.close() else: self.step_label.text = "---" def add_handlers(self): @self.event def on_resize(cx, cy): self.adaptor.screen_resize(cx, cy) pass @self.event def on_mouse_press(x, y, button, modifiers): pass @self.event def on_key_press(symbol, modifiers): # Single Player View, or All View if symbol == key.BRACKETLEFT: self.view_id = self.view_id - 1 if self.view_id > 1 else len(self.game.players) if symbol == key.BRACKETRIGHT: self.view_id = self.view_id + 1 if self.view_id < len(self.game.players) else 1 # Everyone view elif symbol == key.A: self.view_id = 0 # == "all" # Planet attribute type to show? elif symbol == key.L: i = self.label_type l = ['id','num_ships','vision_age','owner_id'] self.label_type = l[l.index(i)+1] if l.index(i) < (len(l)-1) else l[0] # Reset? elif symbol == key.R: self.reset_space() # Do one step elif symbol == key.N: self.game.update() # Pause toggle? elif symbol == key.P: self.paused = not self.paused # Speed up (+) or slow down (-) the sim elif symbol in [key.PLUS, key.EQUAL]: self.set_fps(self.fps + 5) elif symbol == key.MINUS: self.set_fps(self.fps - 5) self.adaptor.sync_all(self.view_id, self.label_type) @self.event def on_draw(): self.clear() self.fps_display.draw() self.step_label.draw() self.adaptor.draw() def set_pen_color(self, color=None, name=None): if name is not None: color = COLOR_NAMES[name] self.curr_color = color glColor4f(*self.curr_color) def set_stroke(self, stroke): self.stroke = stroke glLineWidth(self.stroke) def circle(self, pos, radius, color=None, filled=True): if color: self.set_pen_color(color) if filled: gluQuadricDrawStyle(self.qobj, GLU_FILL) else: gluQuadricDrawStyle(self.qobj, GLU_SILHOUETTE) glPushMatrix() glTranslatef(pos[0], pos[1], 0.0) gluDisk(self.qobj, 0, radius, 32, 1) glPopMatrix() def line(self, x1=0, y1=0, x2=0, y2=0, pos1=None, pos2=None): ''' Draw a single line. Either with xy values, or two position (that contain x and y values). Uses existing colour and stroke values. ''' if pos1 is not None and pos2 is not None: x1, y1, x2, y2 = pos1[0], pos1[1], pos2[0], pos2[1] glBegin(GL_LINES) glVertex2f(x1, y1) glVertex2f(x2, y2) glEnd()
# You don't need to change this function def do_turn(state): behavior_tree.execute(planet_wars) if __name__ == '__main__': logging.basicConfig(filename=__file__[:-3] + '.log', filemode='w', level=logging.DEBUG) behavior_tree = setup_behavior_tree() try: map_data = '' while True: current_line = input() if len(current_line) >= 2 and current_line.startswith("go"): planet_wars = PlanetWars(map_data) do_turn(planet_wars) finish_turn() map_data = '' else: map_data += current_line + '\n' except KeyboardInterrupt: print('ctrl-c, leaving ...') except Exception: traceback.print_exc(file=sys.stdout) logging.exception("Error in bot.")
class Engine(Debuggable): def __init__(self, mapp, enemy_cmd, my_bot_class, timeout=1000, max_turns=200): super(Engine, self).__init__() self.mapp = mapp self.timeout = timeout self.max_turns = max_turns self.enemy_cmd = enemy_cmd self.pw = PlanetWars() try: self.my_bot = my_bot_class() except: self.my_bot = None self.debug_name = "engine" self.playback = "" @property def turn(self): return self.pw.turn def plus_turn(self): self.pw.turn += 1 def load_map_data(self): f = open(self.mapp) data = "\n".join([line for line in f]) f.close() return data def load_init_state(self): '''load map data and make initial game state''' self.pw = PlanetWars() self.pw.load_data(self.load_map_data()) self.playback = ":".join(["%.10f,%.10f,%d,%d,%d" % (p.x, p.y, p.owner, p.num_ships, p.growth_rate) for p in self.pw.planets]) + "|" def _departure(self, enemy_fleets, my_fleets): for i, fleets in enumerate((my_fleets, enemy_fleets,)): for src, dest, num_ships in fleets: dist = self.pw.distance(src,dest) self.pw.fleets.append(Fleet(i+1,num_ships,src,dest,dist,dist)) #TODO make check for ships availability self.pw.planets[src].num_ships -= num_ships def _advancement(self): for fl in self.pw.fleets: fl.turns_remaining -= 1 for pl in self.pw.planets: if pl.owner > 0: pl.num_ships += pl.growth_rate def _get_participants(self, pl): participants = {pl.owner:pl.num_ships} updated_fleets = [] for fl in self.pw.fleets: if fl.dest == pl.id and fl.turns_remaining <= 0: if not fl.owner in participants: participants[fl.owner] = fl.num_ships else: participants[fl.owner] += fl.num_ships else: updated_fleets.append(fl) self.pw.fleets = updated_fleets return participants def _get_winner_second(self, participants): winner = Fleet(0, 0) second = Fleet(0, 0) for k, v in participants.items(): if v > second.num_ships: if v > winner.num_ships: second = winner winner = Fleet(k, v) else: second = Fleet(k, v) return winner, second def _process_arrival(self, pl, winner, second): if winner.num_ships > second.num_ships: pl.num_ships = winner.num_ships - second.num_ships pl.owner = winner.owner else: pl.num_ships = 0 def _arrival(self): for pl in self.pw.planets: participants = self._get_participants(pl) winner, second = self._get_winner_second(participants) self._process_arrival(pl, winner, second) def game_state_update(self, enemy_fleets, my_fleets): self._departure(enemy_fleets, my_fleets) self._advancement() self._arrival() @property def winner(self): return "Old" if self.pw.winner == 2 else "New" if self.pw.winner == 1 else "Draw" def set_enemy_standard_io(self): process = subprocess.Popen(self.enemy_cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) self.stdin, self.stdout = process.stdin, process.stdout def run(self): self.load_init_state() self.set_enemy_standard_io() self.my_bot.via_standard_io = False try: while True: self.make_turn() except EndOfTheGame: return def communicate_enemy_bot(self): self.stdin.write(self.pw.repr_for_enemy() + "go\n") self.stdin.flush() enemy_orders = [] while True: line = self.stdout.readline().replace("\n", "") self.debug("> %s" % line) self.print_it("> %s" % line) if line.startswith("go"): break enemy_orders.append(map(int, line.split(" "))) return enemy_orders def communicate_my_bot(self): self.my_bot.load_data(repr(self.pw)) self.my_bot.do_turn() self.print_it("\n".join(["< %d %d %d" % order for order in self.my_bot.real_orders])) def make_turn(self): self.plus_turn() self.print_it("Turn #%d" % self.turn) self.pw.is_game_over(self.max_turns) enemy_orders = self.communicate_enemy_bot() self.communicate_my_bot() self.game_state_update(enemy_orders, self.my_bot.real_orders) self.print_play_back() def print_play_back(self): if self.debug_enabled: planets = ["%d.%d" % (p.owner, p.num_ships) for p in self.pw.planets] fleets = ["%d.%d.%d.%d.%d.%d" % (f.owner, f.num_ships, f.src, f.dest, f.total_trip_length, f.turns_remaining) for f in self.pw.fleets] self.playback += ",".join(planets + fleets) + ":"