#/usr/bin/python2

# 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(host,port): # do the stuff
  global Jiff
  global w
  w = Bot.World((host, int(port)))
  Jiff = w.jiff

  while (1):
    cmd = find_move(w)
    bid = 1
    fstr = w.bot.make_move(bid, cmd)
    w.io.write(fstr)
    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
  foo(sys.argv[1], sys.argv[2])
