Commits

David Jones  committed 1c76f34

updates.

  • Participants
  • Parent commits c4bd05c

Comments (0)

Files changed (1)

     """
     This is where all of the game state stuff is calculated.
     """
+
+    # This code is called a lot, so this is where I check for
+    # timeouts.
     if time.time() > self.end_time:
-      
       raise OutOfTime()
+
     pw = self.pw
     self.fleets = load_fleets(pw.planets, pw.fleets, self.max_turn)
     self.futures = [run_planet(self.pw.planets[i], self.fleets[i])
     a defense the same turn I attack.  1 means that they don't defend
     until the next turn.
     """
+
     debug("looking at enemy: %d", idx)
     rate = self.pw.planets[idx].growth_rate
     fleets = self.fleets[idx]
     do_debug = False
 
     for (d,src) in dists:
+      # walk from farthest to nearest.
+      # quit if this planet is too far, or if all the needed
+      # ships are fired.
+      
       if d  > target_turn:
         debug("%d is too far", src)
         break
       if not av:
         # debug("HERE %d %s",src, self.my_available)
         continue
-      
+
+
+      # for the current and future turns,
+      # fire as many ships as are available, until we have
+      # fired enough.
       for i in xrange(1,self.max_turn):
         if (i - 1) + d > target_turn:
           break
                 n, src, i, dst, target_turn)
           
           arrive = max(i+d-1, first_turn)
+
+          # the "orders" member is what will get used later...
           self.orders.append((i, src, dst, n, d, first_turn))
           self.pw.fleets.append(Fleet(1,-n,src,src,i-1,i-1))
           self.pw.fleets.append(Fleet(1,n,src,dst,arrive, arrive)) 
     #   debug_list("fleets", self.pw.fleets)
 
   def move_forward(self):
+    """
+    Advance ships to the planets at the front.
+
+    A planet is at the front if it is the closest to any
+    enemy planet of all of my planets.
+
+    This code looks at the future ownership of planets, not
+    current, so it reinforces stuff that I am capturing.
+    """
     futures = self.futures
     srcs = [i for i in self.pidx
             if futures[i][-1][1] == 1]
     return [p for p in self.pidx if self.futures[p][-1][1] == player]
 
   def make_decision(self, ignored=None, offset=0, take_neutrals=True):
+    """
+    This is the function that finds possible shots.  In the 2-ply bot,
+    this is the move generator.
+
+    Creates a list of possible targets, enemy and neutral.  If
+    the list is non-empty, sorts by some random criteria and
+    returns an answer.
+
+    If the list is empty, returns None.
+
+    ignored is here, because if the 2-ply code decides a shot is bad,
+    I don't want to keep evaluating it.  Oh, this code gets
+    called repeatedly.  The bot finds one target at a time until
+    time runs out.
+    
+    """
+
+    # clean out the target list if there are any ignored planets.
     if ignored is None:
       targets = list(self.pidx)
     else:
       targets = [x for x in self.pidx if x not in ignored]
-    
-    # defend what I can
-    # protect what I can
-    # attack enemy planets
-    # move forward
-    # self.shots = []
+
     self.update_state()
-    # defend planets I own
 
     #
     # Attack enemy planets
                                 offset, False)
 
     # enemies = [x for x in enemies if x["target_turn"] < self.max_turn / 2 + 2]
+
     
     for x in enemies:
-      # x["best_est"] = - 2*x["rate"] * (self.max_turn - x["target_turn"]) + x["num"]
       x["best_est"] = x["target_turn"] + x["num"] / (2*x["rate"]  + 0.01)
 
     debug_list("enemies", enemies)
     all_targets = list(enemies)
     
-
     if take_neutrals:
       neutrals = self.find_neutrals([i for i in targets
                                      if self.futures[i][-1][1] == 0])
 
-      # neutrals = [x for x in neutrals if x["target_turn"] < self.max_turn / 2 + 2]
+
       for x in neutrals:
         x["best_est"] = x["target_turn"] + x["num"] / (x["rate"]  + 0.01)      
-        # x["best_est"] = - x["rate"] * (self.max_turn - x["target_turn"]) + x["num"]
 
       debug_list("neutrals", neutrals)
 
       self.fire(all_targets[0])
       return all_targets[0]["planet"]
 
-    # should we need this here?  I don't think so...
-    # self.move_forward()
-
     return None
 
 def neg(xs):
+  """Negate all the components of a score list"""
   return [-x for x in xs]
 
 class Bot1Ply:
+  """
+  1 ply or 2 ply?  I don't know...
+
+  Basically, pick a move, and see if it makes my score better.
+  If it does, make the move.  If it doesn't, ignore it and
+  search again.  Loops over and over for a maximum number of
+  times or until out of time.
+
+  Keeps track of the moves it makes by adding fleets to the PlanetWars
+  structure.  Future shots are marked by creating both a negative
+  fleet arriving at the src planet the turn before launch, and a
+  positive fleet arriving at the dst planet at the desired turn.
+
+  """
+  
   def __init__(self, pw, end_time):
     self.pw = pw
     self.end_time = end_time
     self.logger = logging.getLogger("1ply")
     
   def enemy_move(self, pw, beta, limit=20):
+    """
+    Find the enemies response.  beta is like the alpha-beta cutoff.
+    The bot doesn't have to consider moves that get better than
+    beta.
+
+    Follows the same algorithm i use for my moves.  call `make_decision`,
+    see if the score is better.  if it is, keep it.  if not, throw it out.
+
+    A bad thing here is that the bot only considers moves I think are good.
+
+    """
     end_time = self.end_time
     best_score = [-9e99,-9e99]
     ignored = set()
     logger = self.logger
     logger.debug("in enemy move, beta=%s", beta)
+
+    # find the score for the enemy to do nothing.  We know they will
+    # do at least that good.
     state = Analysis(pw,False, end_time=end_time)
     state.update_state()
     best_score = state.score()
         # update the pw state
         logger.debug("en_move: new best score.")
         best_score = score
-        pw = state.pw
+        # update the pw structure to include the one with the new
+        #  enemy fleets.
+        pw = state.pw  
       else:
       # elif state.shots is None:
         logger.debug("en_move: not using that shot...")
       if target is None:
         break
 
+      # hmmm... this looks pretty redundant.
       if kk < limit - 1:
         state = Analysis(pw,False, end_time=end_time)
         state.update_state()
     # Figure out which planets are always mine.  We are
     # going to use them as way points.
 
+    # find planets that are never the enemies.
     mine = []
     for idx in state.pidx:
       is_mine = False
         if owner == 1: is_mine = True
       else:
         if is_mine:
-          mine.append(idx)          
+          mine.append(idx)
+
+          
     debug("planets that are always mine: %s", mine)
 
     for (turn, src, dst, num, dist, first_turn) in orders:
+      # only call issueorder here.
       if turn == 1 and dist >= first_turn:
         logger.debug("ACTUAL FIRING (AA) s:%d d:%d n:%d", src, dst, num)
         state.pw.IssueOrder(src,dst,num)
+
       elif turn == 1:
         # try to hop the shot...
         # find another of my planets, closer to dst than src,
           state.pw.IssueOrder(src, best_m, num)
 
   def go(self, first_turn=False):
+    """
+    The main function.
+
+    Find the score of me doing nothing, and letting the enemy move.
+
+    Then, generate moves, and consider enemy responses.
+
+    
+
+
+    """
     end_time = self.end_time
     # upper bound on best move.
     beta = [9e99, 9e99]
         state = Analysis(pw_copy, False, end_time=end_time)
         logger.debug("searching for a move")
 
-        # state.update_state()
-        # counts, rates = state.get_end_rates()
-        # logger.debug("foobar counts: %s, rates: %s", counts, rates)
-        # target = state.make_decision(ignored, take_neutrals=(counts[1] < counts[2]))
-
         target = state.make_decision(ignored, take_neutrals=(best_score[0] < -1))
-
-        logger.debug("foobar found move, target:%s, orders: %s", target, state.orders)
-
-
-
-        new_state, score = self.enemy_move(flip_planetwars(state.pw), neg(best_score))
+        new_state, score = self.enemy_move(flip_planetwars(state.pw),
+                                           neg(best_score))
         score = neg(score)
-        logger.debug("MINE: target: %s score: %s  (Best: %s)", target, score, best_score)
-
+        logger.debug("MINE: target: %s score: %s  (Best: %s)",
+                     target, score, best_score)
 
         if score >= best_score: # and state.orders is not None:
           logger.debug("got a new best score: %s  (old %s)", score, best_score)
           logger.debug("state.orders: %s", state.orders)
           best_score = score
           self.fire_orders(state, state.orders)
-          # for (turn, src, dst, num, dist, first_turn) in state.orders:
-          #   if turn == 1 and dist >= first_turn:
-          #     logger.debug("ACTUAL FIRING (AA) s:%d d:%d n:%d", src, dst, num)
-          #     pw.IssueOrder(src,dst,num)
+          # update the state to include the new fleets.
           pw = state.pw
         else:
           logger.debug("ignoring target: %s", target)
 
     except OutOfTime:
       debug("ran out of time.")
+    # funnel forward.
     state = Analysis(pw, False, end_time=end_time)
     state.update_state()
     state.move_forward()
         
 
 def main_do_turn(map_data, turn, end_time):
+  """
+
+  Yet another main function.
+
+  Look, the turn number!  Too bad I ignore it.
+
+  """
+  
   start_time = time.time()
 
   pw = PlanetWars(map_data)
 
-  if False and turn == 1:
-    weights = create_weights(pw)
-    output = ["{x: %f, y: %f, idx: %d, rate: %d, weight: %.1f}" %
-              (p.x, p.y, p.planet_id, p.growth_rate, weights[i])
-              for (i,p) in enumerate(pw.planets)]
-    debug("weights: \n[%s]", ",\n".join(output))
-
-  # if turn == 1:
-  # find_max_distance(pw, True)
-
-  counts = [0,0,0]
-  rates = [0,0,0]
-  for p in pw.planets:
-    counts[p.owner] += p.num_ships
-    rates[p.owner] += p.growth_rate
-  for f in pw.fleets:
-    counts[f.owner] += f.num_ships
-
-  if turn % 5 == -1:          
-    logging.info("turn number: %d", turn)
-    logging.info("player 1: %d/%d", counts[1], rates[1])
-    logging.info("player 2: %d/%d", counts[2], rates[2])
-  else:
-    logging.debug("aaa turn number: %d", turn)
-    logging.debug("aaa player 1: %d/%d", counts[1], rates[1])
-    logging.debug("aaa player 2: %d/%d", counts[2], rates[2])            
-
   try:
-    # bot = BotAlphaBeta(pw, end_time)
     bot = Bot1Ply(pw, end_time)
-    #bot = BotEnFirst(pw, end_time)        
     bot.go(turn==1)
   except OutOfTime:
     debug("caught out of time")
     # SUBMIT_CHECK
     turn_time = 0.8
     if len(argv) > 0:
+
+      # leftover  from the early days when the tcp server, official server,
+      # and playgame.jar file played differently.  
       # TURNFUDGE = 1
+      
       logging.basicConfig(filename=argv[0],
                           level=logging.DEBUG,
                           filemode="w")
-      logger = logging.getLogger()
-      ch = logging.StreamHandler()
-      ch.setLevel(logging.INFO)
-      logger.addHandler(ch)
-      debug("starting logging")
+
       if len(argv) > 1:
         turn_time = float(argv[1])
     main(turn_time)