def __init__(self, element, companies): """Create a passenger from XML and a list of Company objects. name -- The name of this passenger. pointsDelivered -- The number of points a player get for delivering this passenger. car -- The limo the passenger is currently in. None if they are not in a limo. lobby -- The bus stop the passenger is currently waiting in. None if they are in a limo or if they have arrived at their final destination. destination -- The company the passenger wishes to go to next. This is valid both at a bus stop and in a car. It is None of they have been delivered to their final destination. route -- The remaining companies the passenger wishes to go to after destination, in order. This does not include their current destination. enemies -- List of other Passenger objects. If any of them are at a bus stop, this passenger will not exit the limo at that stop. If a passenger at the bus stop has this passenger as an enemy, this passenger can still exit the car. """ self.name = element.get('name') self.pointsDelivered = int(element.get('points-delivered')) lobby = element.get('lobby') self.lobby = ([c for c in companies if c.name == lobby][0] if lobby is not None else None) dest = element.get('destination') self.destination = ([c for c in companies if c.name == dest][0] if dest is not None else None) route = [] for routeElement in element.findall('route'): debug.trap() route.append([c for c in companies if c.name == routeElement.text][0]) self.route = route self.enemies = [] self.car = None
def updatePassengersFromXml (passengers, companies, element): for psgrElement in element.findall('passenger'): #debug.bugprint('updatePassengers XML:', ET.tostring(psgrElement)) #debug.bugprint(' passengers: ' + str(passengers)) passenger = [p for p in passengers if p.name == psgrElement.get('name')][0] dest = psgrElement.get('destination') if dest is not None: passenger.destination = [c for c in companies if c.name == dest][0] # remove from the route if passenger.destination in passenger.route: passenger.route.remove(passenger.destination) # set props based on waiting, travelling, done switch = psgrElement.get('status') if switch == "lobby": passenger.lobby = [c for c in companies if c.name == psgrElement.get('lobby')][0] passenger.car = None elif switch == "travelling": passenger.lobby = None # passenger.car set in Player update elif switch == "done": debug.trap() passenger.destination = None passenger.lobby = None passenger.car = None else: raise TypeError("Invalid passenger status in XML: %r" % switch)
def getData(socket, callback): try: # compute the length of the message (4 byte, little-endian) recstr = socket.recv(4) while len(recstr) < 4: recstr += socket.recv(4 - len(recstr)) assert len(recstr) == 4 lenstr = ["{:02x}".format(ord(char)) for char in recstr] lenstr.reverse() length = int(''.join(lenstr), 16) # receive message into buffer data = socket.recv(length) received = len(data) buff = [] while received < length: buff.append(data) data = socket.recv(length - received) received += len(data) else: assert received == length if buff: buff.append(data) data = ''.join(buff) return data except sock.timeout: trap("Socket operation (receive) timed out") return None except sock.error as err: # fix this if err.errno == 10054: # The connection has been reset. callback.connectionLost(err) else: printrap("WARNING - socket error on receive: " + str(err)) # fix this raise err
def updatePassengersFromXml(passengers, players, companies, element): for psgrElement in element.findall('passenger'): #debug.bugprint('updatePassengers XML:', ET.tostring(psgrElement)) #debug.bugprint(' passengers: ' + str(passengers)) passenger = [p for p in passengers if p.name == psgrElement.get('name')][0] dest = psgrElement.get('destination') if dest is not None: passenger.destination = [c for c in companies if c.name == dest][0] # remove from the route if passenger.destination in passenger.route: passenger.route.remove(passenger.destination) passenger.route = [] dest = psgrElement.get("route") if dest is not None: companyNames = dest.split(";") companyNames = [x for x in companyNames if x] for nameOn in companyNames: passenger.route.append([c for c in companies if c.name == nameOn]) # set props based on waiting, travelling, done switch = psgrElement.get('status') assert switch in PSNGR_STATUS if switch == "lobby": cmpny = [c for c in companies if c.name == psgrElement.get('lobby')][0] passenger.lobby = cmpny passenger.car = None if not (passenger in cmpny.passengers): cmpny.passengers.append(passenger) for plyrOn in players: if plyrOn.limo.passenger == passenger: plyrOn.limo.passenger = None for cmpyOn in companies: if cmpyOn != cmpny: if passenger in cmpyOn.passengers: cmpyOn.passengers.remove(passenger) elif switch == "travelling": plyr = [p for p in players if p.name == psgrElement.get('limo-driver')][0] passenger.car = plyr.limo passenger.lobby = None for plyrOn in players: if (plyrOn != plyr and plyrOn.limo.passenger == passenger): plyrOn.limo.passenger = None for cmpyOn in companies: if passenger in cmpyOn.passengers: cmpyOn.passengers.remove(passenger) # passenger.car set in Player update elif switch == "done": debug.trap() passenger.destination = None passenger.lobby = None passenger.car = None else: raise TypeError("Invalid passenger status in XML: %r" % switch)
def cardDestination(gameMap, startLocation, cards): '''Return the MovePoint resulting from applying cards at startLocation. Ignores all robots on the map but does take into account walls, conveyor belts and gears. Returns the final location of the move. gameMap -- the current state of the game map. startLocation -- the starting BoardLocation of the move. cards -- list of robot Card moves, to be applied in order. ''' points = cardPath(gameMap, startLocation, cards) if points is None or len(points) == 0: trap() return None else: return points[-1]
def updatePassengersFromXml(passengers, companies, element): for psgrElement in element.findall('passenger'): #debug.bugprint('updatePassengers XML:', ET.tostring(psgrElement)) #debug.bugprint(' passengers: ' + str(passengers)) passenger = [ p for p in passengers if p.name == psgrElement.get('name') ][0] dest = psgrElement.get('destination') if dest is not None: passenger.destination = [c for c in companies if c.name == dest][0] # remove from the route if passenger.destination in passenger.route: passenger.route.remove(passenger.destination) # set props based on waiting, travelling, done switch = psgrElement.get('status') if switch == "lobby": cmpny = [ c for c in companies if c.name == psgrElement.get('lobby') ][0] if passenger.lobby != cmpny: passenger.lobby = cmpny if not (passenger in passenger.lobby.passengers): passenger.lobby.passengers.append(passenger) passenger.car = None elif switch == "travelling": if passenger.lobby != None: passenger.lobby.passengers.remove(passenger) passenger.lobby = None # passenger.car set in Player update elif switch == "done": debug.trap() passenger.destination = None passenger.lobby = None passenger.car = None else: raise TypeError("Invalid passenger status in XML: %r" % switch)
def recalculateDistance(self, mapTileCaller, remainingSteps): neighbors = self.neighbors trap(self.costToEnd == 0) # if no neighbors then this is in notEvaluated and so can't recalculate. if len(neighbors) == 0: return shortestDistance = None # if just one neighbor, then it's a dead end if len(neighbors) == 1: shortestDistance = DEAD_END else: shortestDistance = min(neighbors, key=lambda n: n.costToEnd).costToEnd # it's 1+ lowest neighbor value (unless a dead end) if shortestDistance != DEAD_END: shortestDistance += 1 # no change, no need to recalc neighbors if shortestDistance == self.costToEnd: return # new value (could be shorter or longer) self.costToEnd = shortestDistance # if gone too far, no more recalculate if remainingSteps < 0: return remainingSteps -= 1 # need to tell our neighbors - except the one that called us newNeighbors = [n for n in neighbors if n.mapTile != mapTileCaller] for neighborOn in newNeighbors: neighborOn.recalculateDistance(self.mapTile, remainingSteps) # and we re-calc again because that could have changed our neighbors' values shortestDistance = min(neighbors, key=lambda n: n.costToEnd).costToEnd # it's 1+ lowest neighbor value (unless a dead end) if shortestDistance != DEAD_END: shortestDistance += 1 self.costToEnd = shortestDistance
def recalculateDistance(self, mapTileCaller, remainingSteps): neighbors = self.neighbors trap(self.distance == 0) # if no neighbors then this is in notEvaluated and so can't recalculate. if len(neighbors) == 0: return shortestDistance = None # if just one neighbor, then it's a dead end if len(neighbors) == 1: shortestDistance = DEAD_END else: shortestDistance = min(neighbors, key=lambda n: n.distance).distance # it's 1+ lowest neighbor value (unless a dead end) if shortestDistance != DEAD_END: shortestDistance += 1 # no change, no need to recalc neighbors if shortestDistance == self.distance: return # new value (could be shorter or longer) self.distance = shortestDistance # if gone too far, no more recalculate if remainingSteps < 0: return remainingSteps -= 1 # need to tell our neighbors - except the one that called us newNeighbors = [n for n in neighbors if n.mapTile != mapTileCaller] for neighborOn in newNeighbors: neighborOn.recalculateDistance(self.mapTile, remainingSteps) # and we re-calc again because that could have changed our neighbors' values shortestDistance = min(neighbors, key=lambda n: n.distance).distance # it's 1+ lowest neighbor value (unless a dead end) if shortestDistance != DEAD_END: shortestDistance += 1 self.distance = shortestDistance
def incomingMessage(self, message): try: startTime = time.clock() # get the XML - we assume we always get a valid message from the server. xml = ET.XML(message) name = xml.tag if name == "setup": print("Received setup message") # TODO: logging players = api.units.playersFromXml(xml.find("players")) companies = api.map.companiesFromXml(xml.find("companies")) passengers = api.units.passengersFromXml(xml.find("passengers"), companies) map = api.map.Map(xml.find("map"), companies) self.guid = xml.attrib["my-guid"] me2 = [p for p in players if p.guid == self.guid][0] self._brain.setup(map, me2, players, companies, passengers, self.client) ###self.client.sendMessage(ET.tostring(doc)) elif name == "status": # may be here because re-started and got this message before # the re-send of setup if self.guid is None or len(self.guid) == 0: trap() return status = xml.attrib["status"] attr = xml.attrib["player-guid"] guid = attr if attr is not None else self.guid brain = self._brain if self.lock.acquire(False): try: api.units.updatePlayersFromXml(brain.players, brain.passengers, xml.find("players")) api.units.updatePassengersFromXml(brain.passengers, brain.companies, xml.find("passengers")) # update my path & pick-up playerStatus = [p for p in brain.players if p.guid == guid][0] elem = xml.find("path") # bugprint('framework.py: path element ->', ET.tostring(elem)) if elem is not None and elem.text is not None: path = [item.strip() for item in elem.text.split(";") if len(item.strip()) > 0] del playerStatus.limo.path[:] for stepOn in path: pos = stepOn.index(",") playerStatus.limo.path.append((int(stepOn[:pos]), int(stepOn[pos + 1 :]))) elem = xml.find("pick-up") # bugprint('framework.py: pick-up element ->', ET.tostring(elem)) if elem is not None and elem.text is not None: names = [item.strip() for item in elem.text.split(";") if len(item) > 0] playerStatus.pickup = [p for p in brain.passengers if p.name in names] # pass in to generate new orders brain.gameStatus(status, playerStatus, brain.players, brain.passengers) # except Exception as e: # raise e finally: self.lock.release() else: # failed to acquire the lock - we're throwing this message away. trap() return elif name == "exit": print("Received exit message") # TODO: logging sys.exit(0) else: printrap("ERROR: bad message (XML) from server - root node %r" % name) turnTime = time.clock() - startTime prefix = "" if turnTime < 0.8 else "WARNING - " prefix = "!DANGER! - " if turnTime >= 1.2 else prefix print(prefix + "turn took %r seconds" % turnTime) # TODO: logging except Exception as e: traceback.print_exc() printrap("Error on incoming message. Exception: %r" % e)
def statusMessage(self, message): trap() print(message)
def incomingMessage(self, message): try: startTime = time.clock() # get the XML - we assume we always get a valid message from the server. xml = ET.XML(message) name = xml.tag if name == 'setup': players = None companies = None passengers = None stores = None powerups = None map = None print ("Received setup message") players = api.units.playersFromXml(xml.find("players")) companies = api.map.companiesFromXml(xml.find("companies")) passengers = api.units.passengersFromXml(xml.find("passengers"), companies) stores = api.map.coffeeFromXml(xml.find("stores")) powerups = api.units.powerUpFromXml(xml.find("powerups"), companies, passengers) map = api.map.Map(xml.find("map"), companies) self.guid = xml.attrib["my-guid"] me2 = [p for p in players if p.guid == self.guid][0] self.brain.setup(map, me2, players, companies, passengers, self.client, stores, powerups, framework) ###self.client.sendMessage(ET.tostring(doc)) elif name == 'status': # may be here because re-started and got this message before # the re-send of setup if self.guid is None or len(self.guid) == 0: trap() return status = xml.attrib["status"] attr = xml.attrib["player-guid"] guid = attr if attr is not None else self.guid brain = self.brain if self.lock.acquire(False): try: api.units.updatePlayersFromXml(brain.companies, brain.players, brain.passengers, xml.find("players")) api.units.updatePassengersFromXml(brain.passengers, brain.players, brain.companies, xml.find("passengers")) # update my path & pick-up playerStatus = [p for p in brain.players if p.guid == guid][0] elem = xml.find("path") #bugprint('framework.py: path element ->', ET.tostring(elem)) if elem is not None and elem.text is not None: path = [item.strip() for item in elem.text.split(';') if len(item.strip()) > 0] del playerStatus.limo.path[:] for stepOn in path: pos = stepOn.index(',') playerStatus.limo.path.append((int(stepOn[:pos]), int(stepOn[pos + 1:]))) elem = xml.find("pick-up") #bugprint('framework.py: pick-up element ->', ET.tostring(elem)) if elem is not None and elem.text is not None: names = [item.strip() for item in elem.text.split(';') if len(item) > 0] playerStatus.pickup = [p for p in brain.passengers if p.name in names] # pass in to generate new orders brain.gameStatus(status, playerStatus) #except Exception as e: # raise e finally: self.lock.release() else: # failed to acquire the lock - we're throwing this message away. trap() return elif name == "powerup-status": brain = self.brain if self.guid is None: return if self.lock.acquire(False): try: puStatus = xml.attrib["status"] puGuid = xml.attrib["played-by"] if xml.attrib["played-by"] is not None else self.guid plyrPowerUp = next(g for g in brain.players if g.guid == puGuid) cardPlayed = api.units.powerUpGenerateFlyweight(xml.find("card"), brain.companies, brain.passengers, brain.players) # do we update the card deck? if (cardPlayed == cardLastPlayed or ( datetime.datetime.now() > cardLastSendTime + datetime.timedelta(seconds=1))): updateCards(brain, xml.find("cards-deck").findall("card"), brain.powerUpDeck, brain.powerUpHand) updateCards(brain, xml.find("cards-hand").findall("card"), brain.powerUpHand, None) brain.powerUpStatus(puStatus, plyrPowerUp, cardPlayed) finally: self.lock.release() else: # failed to acquire the lock - we're throwing this message away. trap() return elif name == 'exit': print("Received exit message") sys.exit(0) else: printrap("ERROR: bad message (XML) from server - root node %r" % name) turnTime = time.clock() - startTime prefix = '' if turnTime < 0.8 else "WARNING - " prefix = "!DANGER! - " if turnTime >= 1.2 else prefix # print(prefix + "turn took %r seconds" % turnTime) Enable this to see turn speed except Exception as e: traceback.print_exc() printrap("Error on incoming message. Exception: %r" % e)
def calculatePath(gmap, start, end): """Calculate and return a path from start to end. This implementation is intentionally stupid and is NOT guaranteed in any way. Specifically, although it may, it is not guaranteed to: ->Return the shortest possible path ->Return a legal path ->Return in a reasonable amount of time ->Be free of bugs Use unmodified at your own risk. map -- The game map. start -- The tile units of the start point (inclusive). end -- The tile units of the end point (inclusive). """ # should never happen but just to be sure if start == end: return [start] # nodes are points we have walked to nodes = {} # points we have in a trailPoint, but not yet evaluated notEvaluated = [] tpOn = TrailPoint(start, end, 0) while True: nodes[tpOn.mapTile] = tpOn # get the neighbors tpClosest = None for ptOffset in OFFSETS: pointNeighbor = (tpOn.mapTile[0] + ptOffset[0], tpOn.mapTile[1] + ptOffset[1]) square = gmap.squareOrDefault(pointNeighbor) # off the map or not a road/bus stop if square is None or (not square.isDriveable()): continue # already evaluated - add it in if pointNeighbor in nodes: tpAlreadyEvaluated = nodes[pointNeighbor] tpAlreadyEvaluated.cost = min(tpAlreadyEvaluated.cost, tpOn.cost+1) tpOn.neighbors.append(tpAlreadyEvaluated) continue # add this one in tpNeighbor = TrailPoint(pointNeighbor, end, tpOn.cost+1) tpOn.neighbors.append(tpNeighbor) # may already be in notEvaluated. If so remove it as this is a more # recent cost estimate. if tpNeighbor in notEvaluated: notEvaluated.remove(tpNeighbor) # we only assign to tpClosest if it is closer to the destination. # If it's further away, then we use notEvaluated below to find the # one closest to the dest that we ahve not walked yet. if tpClosest is None: if tpNeighbor.distance < tpOn.distance: # new neighbor is closer - work from this next tpClosest = tpNeighbor else: # this is further away - put in the list to try if a # better route is not found notEvaluated.append(tpNeighbor) else: if tpClosest.distance <= tpNeighbor.distance: # this is further away - put in the list to try if a # better route is not found notEvaluated.append(tpNeighbor) else: # this is closer than tpOn and another neighbor - use it next. notEvaluated.append(tpClosest) tpClosest = tpNeighbor # re-calc based on neighbors tpOn.recalculateDistance(POINT_OFF_MAP, gmap.width) # if no closest, then get from notEvaluated. This is where it # guarantees that we are getting the shortest route - we go in here # if the above did not move a step closer. This may not either as # the best choice may be the neighbor we didn't go with above - but # we drop into this to find the closest based on what we know. if tpClosest is None: if len(notEvaluated) == 0: trap() break # we need the closest one as that's how we find the shortest path tpClosest = notEvaluated[0] for tpNotEval in notEvaluated: if tpNotEval.distance < tpClosest.distance: tpClosest = tpNotEval notEvaluated.remove(tpClosest) # if we're at the end - we're done! if tpClosest.mapTile == end: tpClosest.neighbors.append(tpOn) nodes[tpClosest.mapTile] = tpClosest break # try this one next tpOn = tpClosest # create the return path - from end back to beginning tpOn = nodes[end] path = [tpOn.mapTile] while tpOn.mapTile != start: neighbors = tpOn.neighbors cost = tpOn.cost tpOn = min(neighbors, key=lambda n: n.cost) # we didn't get to the start. if tpOn.cost >= cost: trap() return path else: path.insert(0, tpOn.mapTile) return path
def incomingMessage(self, message): try: startTime = time.clock() # get the XML - we assume we always get a valid message from the server. xml = ET.XML(message) name = xml.tag if name == 'setup': print("Received setup message") #TODO: logging players = api.units.playersFromXml(xml.find("players")) companies = api.map.companiesFromXml(xml.find("companies")) passengers = api.units.passengersFromXml( xml.find("passengers"), companies) map = api.map.Map(xml.find("map"), companies) self.guid = xml.attrib["my-guid"] me2 = [p for p in players if p.guid == self.guid][0] self._brain.setup(map, me2, players, companies, passengers, self.client) ###self.client.sendMessage(ET.tostring(doc)) elif name == 'status': # may be here because re-started and got this message before # the re-send of setup if self.guid is None or len(self.guid) == 0: trap() return status = xml.attrib["status"] attr = xml.attrib["player-guid"] guid = attr if attr is not None else self.guid brain = self._brain if self.lock.acquire(False): try: api.units.updatePlayersFromXml(brain.players, brain.passengers, xml.find("players")) api.units.updatePassengersFromXml( brain.passengers, brain.companies, xml.find("passengers")) # update my path & pick-up playerStatus = [ p for p in brain.players if p.guid == guid ][0] elem = xml.find("path") #bugprint('framework.py: path element ->', ET.tostring(elem)) if elem is not None and elem.text is not None: path = [ item.strip() for item in elem.text.split(';') if len(item.strip()) > 0 ] del playerStatus.limo.path[:] for stepOn in path: pos = stepOn.index(',') playerStatus.limo.path.append( (int(stepOn[:pos]), int(stepOn[pos + 1:]))) elem = xml.find("pick-up") #bugprint('framework.py: pick-up element ->', ET.tostring(elem)) if elem is not None and elem.text is not None: names = [ item.strip() for item in elem.text.split(';') if len(item) > 0 ] playerStatus.pickup = [ p for p in brain.passengers if p.name in names ] # pass in to generate new orders brain.gameStatus(status, playerStatus, brain.players, brain.passengers) #except Exception as e: # raise e finally: self.lock.release() else: # failed to acquire the lock - we're throwing this message away. trap() return elif name == 'exit': print("Received exit message") #TODO: logging sys.exit(0) else: printrap( "ERROR: bad message (XML) from server - root node %r" % name) turnTime = time.clock() - startTime prefix = '' if turnTime < 0.8 else "WARNING - " prefix = "!DANGER! - " if turnTime >= 1.2 else prefix print(prefix + "turn took %r seconds" % turnTime) #TODO: logging except Exception as e: traceback.print_exc() printrap("Error on incoming message. Exception: %r" % e)