# python imports

import sys, random, string, profile
# our imports

import Bot, defs, proc


__version__ = "$Revision: 1.20 $"



import ICFP




global w

w = None



global Jiff

Jiff = None



rand_seed = random.Random() # global random



def rand(max):

  foo = int(max * rand_seed.random())

  return foo



def filter_packs(x):

  global w

  if (not w.py_bots.has_key(id(x)) and x.weight <= w.bot.capacity):

    return 1

  return 0



def good_package(w):

  packs = w.board.extra_here(w.bot.x_pos, w.bot.y_pos)

  if (not packs):

    return None



  can_carry = w.bot.capacity

  pickups = []

  packs = filter(filter_packs, packs)

  if (not packs):

    return None



  f = Bot.FindPackage(w.bot.curr_loc, packs, w.board.C_board)

  f.try_harder()



  packs = f.found_good

  if (not len(packs)):

    packs = [[p,[]] for p in f.found]  # crappier guestimate on ICFP.heuristic1



  for (p) in packs:

    if (can_carry == 0):

      break

    if (can_carry >= p[0].weight):

      pickups.append(p[0].id)

      can_carry -= p[0].weight



#  for (p) in packs2:

#    if (can_carry == 0):

#      break

#    if (can_carry >= p[0].weight):

#      pickups.append(p[0].id)

#      can_carry -= p[0].weight#



  if (pickups):

    pickups = map ( str, pickups )

    return ('Pick ' + string.join(pickups, ' '),)



  return None



def null_distance(x,y):

  return 1



def deliver_package(w):

  b = w.bot

  c_loc = (b.x_pos, b.y_pos)

  if (b.deliverme):

    if (b.deliverme.x_des == b.x_pos and b.deliverme.y_des == b.y_pos):

      return ('Drop %d' % (b.deliverme.id),)

    else:

      f = Bot.FindClose(w.bot.curr_loc, [b.deliverme], w.board.C_board)

      f.try_harder()

      if (not len(f.found_good)):

        return None

      

      if (len(f.found_good[0][1]) <= 1):

        return None

      return ('Move', f.found_good[0][1][1:])

  elif (len(b.packages.keys())):

    b.deliverme = b.packages.values()[0]

    return delier_package()

  return None



def close_home(w):

  b = w.bot

  bases = w.board.d_bases

  if (not bases):

    print 'DONE!' # server connection killed before this

    return None



  f = Bot.FindClose(b.curr_loc, bases, w.board.C_board)

  f.try_harder()

  if (not f.found_good):

    f.try_hardest()



  if (not len(f.found_good)):

    return None



  tryhere = f.found_good[0]

  if (len(f.found_good[0][1]) <= 1):

    return None



  return ('Move', f.found_good[0][1][1:])



def continue_walk(w):

  if (len(w.bot.current_walk) > 10):

    # try a few moves ahead, to give a chance to recalc player avoidance

    goto = w.bot.current_walk[10]

  else:

    goto = w.bot.current_walk[-1]

  w.bot.current_walk.pop(0)

    

  f = Bot.FindClose(w.bot.curr_loc, [Bot.Home(goto)], w.board.C_board)

  f.try_harder()

  if (not len(f.found_good)):

    return None



  return 'Move %s' % (w.bot.rev_move(w.bot.curr_loc, f.found_good[0][1][1]))

    

def wander(w):

  curr_loc = w.bot.curr_loc

  tries = 100

  answer = None

  while (tries):

    nx = curr_loc[0] + 7 - rand(14)

    ny = curr_loc[1] + 7 - rand(14)

    if (nx == curr_loc[0] and ny == curr_loc[1]):

      continue

    if (Jiff.avail < 100000): # cheat

      Jiff.avail = 100000

    f = Bot.FindClose(w.bot.curr_loc, [Bot.Home((nx,ny))], w.board.C_board)

    f.try_harder()

    if (len(f.found_good) and len(f.found_good[0][1])):

      return ('Move', f.found_good[0][1][1:])

    tries -= 1



def nearby_bot(theirbot):

  global w

  ourloc = w.bot.curr_loc

  if (w.bot.id == theirbot.id):

    return 0

  if (ICFP.heuristic1(ourloc, theirbot.curr_loc) <= 2):

    return 1



def find_move(w):

  others = filter (nearby_bot, w.bots.values())

  try_again = 1

  desperate = 0

  curr_move = None



  if (w.bot.current_walk and len(w.bot.current_walk)):

    try:

      curr_move = continue_walk(w)

    except:

      w.bot.current_walk = None

      curr_move = None

    if (curr_move):

      return curr_move



  while (try_again or desperate):

    if (desperate or not others):

      curr_move = good_package(w) # is there a good package to pickup here?



    if (not curr_move):

      curr_move = deliver_package(w) # are we delivering a package?



    # lets find a package

    if (not curr_move):

      try:

        curr_move = close_home(w) # find the closest home

      except:

        curr_move = None



    if (curr_move):

      break



    if (try_again):

      desperate = 1

      try_again = 0



    if (desperate and curr_move == None):

      curr_move = wander(w)

      desperate = 0



  # while (try_again or desperate)



  if (curr_move != None):

    if (curr_move[0] == 'Move'): # we have a list of steps

      w.bot.current_walk = curr_move[1]

      gowhere = w.bot.current_walk.pop(0)

      dir = w.bot.rev_move(w.bot.curr_loc, gowhere)

      return 'Move %s' % (dir)

    else:

      return curr_move[0]

      

  return None



def foo(): # do the stuff

  global Jiff

  global w

  w = Bot.World((defs.HOST, defs.PORT))

  Jiff = w.jiff



  while (1):

    cmd = find_move(w)

    bid = 1

    str = w.bot.make_move(bid, cmd)

    w.io.write(str)

    if (not w.read_server_response()):

      sys.stderr.write("Score was " + str(w.bot.score) + " IN CPU TIME " + str(Jiff.get_jiffies()) + "\n")

      return None

    if (not w.read_packages()):

      sys.stderr.write("Score was " + str(w.bot.score) + " IN CPU TIME " + str(Jiff.get_jiffies()) + "\n")

      # CROSS

      # tag     score  CPU   fuel left

      # GOOD3    400, 0.25

      # GOOD4    400, 0.28     3554

      # GOOD4b   400, 0.35     3616

      # GOOD7    400, 1.00     3773

      # GOOD7b                 3784

      # Bridge

      # tag

      # GOOD5    820  24.58    1418

      # GOOD5b   820  23.46    1418

      # GOOD6    820  4.01     2377

      # GOOD7    820  7.63     2387

      return None



    Jiff.bump_turn()

    w.board.upgrade_bases()

  return



def bar(): # wrapper to foo()

  foo()

  print "FINISHED"

  return



if (len(sys.argv) > 1): # don't run during make check

  #profile.run('foo()')

  foo()

  dummy = 1