def Respawn(self): # Respawn a defeated wall (or restore an attacked wall) self.__climbedAttacker = {"Battalion": None, "SoldierPosition": Point3D()} self.__attachedSiegeTower = {"SiegeTower": None, "Position": Point3D()} self.__climberStairs = [] self.__tilesManager.RecalculateTiles()
def Reset(self): Construction.Construction.Reset(self) # Remove climbers and siege towers self.__climbedAttacker["Battalion"] = None self.__climbedAttacker["SoldierPosition"] = Point3D() self.__attachedSiegeTower["SiegeTower"] = None self.__attachedSiegeTower["Position"] = Point3D() # Clear the list of climbers, but not delete them self.__climberStairs = [] self.__tilesManager.Reset()
def GetBoundingBox(self): quad = self.GetBoundingQuad() if (self.HasBattalion()): bbox = self.GetBattalion().GetBounding() height = bbox.height else: height = 0.0 bbox = BoundingBox(minP=Point3D(quad.minPoint.x, quad.minPoint.y, self.__groundHeight), maxP=Point3D(quad.maxPoint.x, quad.maxPoint.y, self.__groundHeight + height)) return bbox
def AppendBattalion(self, battalion, offset=0): # Appends a battalion that requires size space at next avaiable position # Returns false if there isn't enough space to place the battalion # Parameter offset is used to place the next battalion at offset distance # Calculate next avaiable placement if (len(self._battalions) == 0): pend = self._line.p1.Copy() else: pend = Point2D().SetFrom3D(self._battalions[len(self._battalions) - 1].position.Copy()) dv = self.__GetVector2D() dv.Normalize() pend.Move(dv, (self._gridCellSize) + offset) # Check if new placement has reached the end of defending line dist1 = pend.Distance(self._line.p1) dist2 = pend.Distance(self._line.p2) endreached = (dist2 < self._gridCellSize) or (dist1 > self.__GetLength()) if (endreached): if (len(self._battalions) > 0): return False else: # If there are not enough space to deploy the battalion, but the defense line is empty, means that it is too short, but it is enough large to fit an unit # This can happens if offset is too big if (len(self._battalions) == 0): pend = self._line.GetMidPoint() self._battalions.append( DefendingBattalion(battalion, Point3D(pend.x, pend.y, self._height))) self._battalionsMap[battalion.GetLabel()] = len(self._battalions) - 1 return True
def GetRandomPosition(self): # Get a random point of current battalion. Index is used only for climbing soldiers if (self.__placementType == Placement.BATTLEFIELD): return self.__battlefieldCell.GetRandomCellPosition() elif (self.__placementType == Placement.DEFENDINGLINE): return self.__defendingLine[ "Construction"].GetRandomBattalionCellPosition( self.__defendingLine["DefendingLine"], self.__battalion) elif (self.__placementType == Placement.CLIMBING): # Since the random position on battlefield and defending lines are calculated on the battalion placement, we are going to calculate a bounding around the soldier and # calculate the point on it. To avoid working with a cube (the soldier is moving in all 3 dimensions), we get random positions on the three axis bounding = self.__battalion.GetBounding() #random.seed() rx = random.uniform(0, bounding.length * 2.0) ry = random.uniform(0, bounding.width * 2.0) rz = random.uniform(0, bounding.height * 2.0) pos = self.__climbing["Position"].Copy() # Lets do simplify more and don't consider the wall rotation. This is not accurate, but is much faster than vector operations pos.x = (pos.x - bounding.length) + rx pos.y = (pos.y - bounding.width) + ry pos.z = (pos.z - bounding.height) + rz return pos return Point3D()
def ShootToConstruction(self, target, frompos, targetpos): # Shoots to a construction target. Usually by a cannon # The targetpos parameter is where attacker points. But the precision factor can modify it # In addition, the final shooting point can hit any other construction part (see NOTE bellow) # Returns a dictionary with hit result -> {"Hit": True/False, "Intersection": Point3D()} ret = {"Hit": False, "Intersection": Point3D()} # Aiming consideration: We are going to calculate a shoot in a direction sampled by a cosinus distribution # From the aiming point of view, the shooter points to a far point, and if accuracy factor is 100%, it should hit the target. # So, the sphere used to sample the cosinus distribution should has the target distance as radius. # Then, we can use the accuracy factor to get a percentage of shooting distance. With this consideration, bad accuracy factors means # sampling on small spheres, so the shoot can fail dist = frompos.Distance(targetpos) accuracy = dist * self.__accuracyFactor / 100.0 direction = Vector3D() direction.CreateFrom2Points(frompos, targetpos) sph = Sphere(position=frompos, radius=accuracy) v = sph.GetRayCosine(direction) # Check hit on the castle # NOTE : The intersection test over whole castle geometry has a high cost. The process is simplified considering only target. # If shoot doesn't hits target, the shoot fails ray = Ray(origin=frompos, direction=v, energy=self.__attack) hitpoint = target.RecieveImpact(ray) if (hitpoint != None): ret["Hit"] = True ret["Intersection"] = hitpoint return ret
def __init__(self, battlefield, cells): self.__battlefield = battlefield self.__battlefieldCells = cells self.__closestConstruction = None self.__distanceClosestConstruction = -1 # Calculate the bounding box # Set the cells as trench cells self.__boundingBox = BoundingQuad() if (self.__battlefieldCells): height = 0 for c in self.__battlefieldCells: self.__boundingBox.InsertPoint(c.center) c.SetTrench( self, Battles.Utils.Settings.SETTINGS.Get_F( 'Battlefield', 'Trench', 'DefenseIncrease'), Battles.Utils.Settings.SETTINGS.Get_F( 'Battlefield', 'Trench', 'MovementPenalty')) height += c.GetAltitude() self.__center = Point3D().SetFrom2D(self.__boundingBox.GetCenter()) self.__center.z = height / len(self.__battlefieldCells) self.__useless = False self.__visitedBattalions = []
def ProjectPosition(self, pos): # Projects given position onto the defending line to get a centered good position pos2d = Point2D().SetFrom3D(pos) prj = self._line.ProjectPoint(pos2d) prj3d = Point3D().SetFrom2D(prj) prj3d.z = pos.z return prj3d
def SetDefendingLine(self, construction, defendingline): self.__placementType = Placement.DEFENDINGLINE self.__defendingLine["Construction"] = construction self.__defendingLine["DefendingLine"] = defendingline self.__battlefieldCell = None self.__climbing["Wall"] = None self.__climbing["Position"] = Point3D() self.__climbing["Stair"] = None
def SetBattlefieldCell(self, cell): self.__placementType = Placement.BATTLEFIELD self.__battlefieldCell = cell self.__defendingLine["Construction"] = None self.__defendingLine["DefendingLine"] = -1 self.__climbing["Wall"] = None self.__climbing["Position"] = Point3D() self.__climbing["Stair"] = None
def __init__(self, battalion): self.__battalion = battalion self.__battlefieldCell = None self.__defendingLine = {"Construction": None, "DefendingLine": -1} self.__climbing = {"Wall": None, "Position": Point3D(), "Stair": None} self.__placementType = Placement.UNKNOWN self.__badCells = [] self.__visitedCells = []
def GetRandomCellPosition(self): # Returns an uniform random cell position (well, not exactly an uniform distribution, but near to it) pos = self.center size = self.GetCellSize() #seed() x = uniform(pos.x - (size / 2), pos.x + (size / 2)) y = uniform(pos.y - (size / 2), pos.y + (size / 2)) return Point3D(x, y, pos.z)
def RayHitTest(self, ray): # Do the check in 2D -> easy and cheap (TODO: Do it (well) in 3D) ray2d = Ray2D().SetFrom3D(ray) seglist = self.GetIntersectableSegments() for seg in seglist: if ray2d.HitSegment3(seg): ray.SetHitPoint(Point3D().SetFrom2D(ray2d.GetHitPoint())) return True return False """# Checks if given ray intersects with wall
def __init__(self): Construction.Construction.__init__(self) self._thickness = Battles.Utils.Settings.SETTINGS.Get_F('Castle', 'Wall', 'Thickness') self._height = Battles.Utils.Settings.SETTINGS.Get_F('Castle', 'Wall', 'InnerHeight') self._defenseIncrease = Battles.Utils.Settings.SETTINGS.Get_I('Castle', 'Wall', 'DefenseIncrease') self.__slope = None self.__joins = [None, None] self.__walkway = { "altitude": (self._height - Battles.Utils.Settings.SETTINGS.Get_F('Castle', 'Wall', 'MerlonHeight')), "width": Battles.Utils.Settings.SETTINGS.Get_F('Castle', 'Wall', 'WalkwayWidth')} self._defendingLines = BattalionConstruction.BattalionConstruction(height=self.__walkway["altitude"], cellsize=Battles.Utils.Settings.SETTINGS.Get_F( 'Castle', 'Wall', 'BattalionGridCellSize')) self.__tilesManager = TilesManager.TilesManager(self) self._label = 'Wall_' + str(Wall.wallCounter) Wall.wallCounter += 1 self.__rectangle3D = [Point3D(), Point3D(), Point3D(), Point3D()] self.__boundingRectangle3D = BoundingBox() self.__normalVector = Vector3D() self.__heightCanvasObjs = [] self.__climberStairs = [] self.__climbedAttacker = {"Battalion": None, "SoldierPosition": Point3D()} self.__attachedSiegeTower = {"SiegeTower": None, "Position": Point3D()}
def SetPosition(self, p1, p2, reshape=True): # Sets the wall position with 2 points. If reshape is true, the wall 2D shape is recalculated if p1.Distance(p2) < 5: print "WARNING: Too short wall creation" # return False del self._axis2D[:] self._axis2D.append(Segment2D(p1, p2)) # Generate the wall shape if reshape: self.JoinShape(None) # Recalculates the battalion grid (creates an empty battalion grid) # Note that battalion grid is created over wall axis. The wall shape is not taken into account self._defendingLines.SetDefendingLine(0, self._axis2D[0]) # Recalculates the tiles self.__tilesManager.RecalculateTiles() # Recalculates the 3D rectangle and bounds (used to check shoot hits on wall) # Calculate the exterior wall 3D rectangle self.__rectangle3D[0] = Point3D(self.GetStartPosition().x, self.GetStartPosition().y, 0.0) # self.__rectangle3D[1] = Point3D(self.GetStartPosition().x, self.GetStartPosition().y, self.__walkway["altitude"]) # self.__rectangle3D[2] = Point3D(self.GetEndPosition().x, self.GetEndPosition().y, self.__walkway["altitude"]) self.__rectangle3D[1] = Point3D(self.GetStartPosition().x, self.GetStartPosition().y, self._height) self.__rectangle3D[2] = Point3D(self.GetEndPosition().x, self.GetEndPosition().y, self._height) self.__rectangle3D[3] = Point3D(self.GetEndPosition().x, self.GetEndPosition().y, 0.0) # Calculate the rectangle bounding self.__boundingRectangle3D = BoundingBox() for p in self.__rectangle3D: self.__boundingRectangle3D.InsertPoint(p) # Calculate the exterior normal vector self.CalculateNormalVector() return True
def tick(self, tick): battalion = tick.target selfarmy = tick.blackboard.get('selfarmy', tick.tree.id, None) againstarmy = tick.blackboard.get('againstarmy', tick.tree.id, None) movedList = tick.blackboard.get('movedList', tick.tree.id, None) # Moves troops (usually in battlefield) # The moved troops are stored into movedList (used for drawing update reasons) #print "Army Move!!!", self.GetCommand().GetType() cell = tick.blackboard.get('cell', tick.tree.id, None) # Move troops on the battlefield # ============================================================================= w = cell.GetClosestWall() tilesmanager = w.GetTileManager() # Force the battalion to go to closest gateway (if there are any) instead of climbing # Bet sure that battalion is in front of a gateway gatewayindex = tilesmanager.GetCloseGateway(cell.center, Battles.Utils.Settings.SETTINGS.Get_F('Army', 'Infantry', 'SearchRadiusGoToRumble')) if gatewayindex != None: # Convert all battalion units into "free" climbers and let them to start climbing all together ntroops = battalion.GetNumber() while ntroops > 0: newbattalion = selfarmy.ExtractSoldier(battalion) # Project a random position on the gateway. Be aware about climbers placed just at the tile edges (they should be placed in other tile columns due # precision facts) gp = tilesmanager.GetRandomGatewayPosition(gatewayindex = gatewayindex, marginleft = 0.0, marginright = Battles.Utils.Settings.SETTINGS.Get_F('Army', 'Infantry', 'Bounding/Length') / 2.0) if not gp: print "ERROR: None random gateway position obtained -> Wrong gateway index" return b3.FAILURE gpos = Point3D().SetFrom2D(gp) gpos.z = cell.GetAltitude() # Create a stair for each "free" climber to avoid problems with climbing structure stair = w.CreateClimbingStair(stairposition = gpos, defendersarmy = againstarmy, climber = newbattalion, movedList = movedList) # Set the new soldier placement and command newbattalion._placement.SetClimbingWall(wall = w, stairposition = gpos, clearprevious = False, stair = stair) newbattalion._action.SetCommand(Command.GOTO_CASTLE, w) if movedList: movedList.append(newbattalion) ntroops -= 1 if movedList: movedList.append(battalion) return b3.SUCCESS
def GetTileCenter(self, tile): # Returns the 3D center of given tile # Note that this is the real position, not local wall position vector = Vector2D() vector.CreateFrom2Points(self.__construction.GetStartPosition(), self.__construction.GetEndPosition()) pos = self.__construction.GetStartPosition().Copy() pos.Move(vector, (self.__tileDims["width"] * tile.index["column"]) + (self.__tileDims["width"] / 2)) height = (tile.index["row"] * self.__tileDims["height"]) + (self.__tileDims["height"] / 2) return Point3D(pos.x, pos.y, height)
def __init__(self, battlefield, row, column): self.__battleField = battlefield self.__movementPenalty = Battles.Utils.Settings.SETTINGS.Get_F( 'Battlefield', 'GroundCell', 'MovementPenalty') self.__defenseIncrease = Battles.Utils.Settings.SETTINGS.Get_F( 'Battlefield', 'GroundCell', 'DefenseIncrease') self.__battalion = None self.__index = {"row": row, "column": column} self.__groundHeight = Battles.Utils.Settings.SETTINGS.Get_F( 'Battlefield', 'GroundCell', 'Height') self.__constructions = [] self.__moat = None self.__city = False self.__trench = None self.__river = None cellsize = self.__battleField.GetCellSize() self.center = Point3D( (self.__index["column"] * cellsize) + (cellsize / 2), (self.__index["row"] * cellsize) + (cellsize / 2), self.__groundHeight)
def Project(self, position=Point3D(), wallside=1): # Projects given position over the exterior wall # If wallside is 1, projects over exterior wall. If it is 2, projects over the back wall side. Finally, if it is 3, projects over the medial axis # This is usually used when an attacker needs to be attached to the wall to climb it p = Point2D().SetFrom3D(position) if wallside == 1: prj = self.GetExteriorSegment().ProjectPoint(p) elif wallside == 2: seg = Segment2D(self._shape2D[3], self._shape2D[2]) prj = seg.ProjectPoint(p) elif wallside == 3: seg = Segment2D(self.GetStartPosition(), self.GetEndPosition()) prj = seg.ProjectPoint(p) else: return None position.x = prj.x position.y = prj.y return position
def AppendBattalion(self, battalion, offset=0): # Appends a battalion # Returns false if there isn't enough space to place the battalion # Parameter offset is used to place the next battalion at offset distance - NOT IMPLEMENTED YET -> TODO if (self.GetAvaiableCells(margin=offset) == 0): return False # Calculate next avaiable placement nmax = self.__GetMaxCellsNumber(margin=offset) ang = 360.0 / nmax nextang = (ang * len(self._battalions)) + ang nextang = math.radians(nextang) p = Point2D() p.x = self.__center.x + (math.cos(nextang) * self.__radius) p.y = self.__center.y + (math.sin(nextang) * self.__radius) self._battalions.append( DefendingBattalion(battalion, Point3D(p.x, p.y, self._height))) self._battalionsMap[battalion.GetLabel()] = len(self._battalions) - 1 return True
def GetNearestHolePosition(self, frompos): # Returns the nearest hole position, that is the central tile point of the nearest 0 tile value minD = -1 posMin = Point3D() i = 0 while (i < self.__tilesSize["rows"]): j = 0 while (j < self.__tilesSize["columns"]): if (self.__tiles[i][j].IsHole()): center = self.GetTileCenter(self.__tiles[i][j]) dist = center.Distance(frompos) if ((dist < minD) or (minD == -1)): minD = dist posMin = center j += 1 i += 1 if (minD == -1): return None else: return posMin
def GetRandomCellPosition(self, battalion): # Returns a random position inside battalion cell db = self.GetDefendingBattalion(battalion) if (db == None): print "ERROR: Battalion dont found for GetRandomCellPosition" return None vector = self.__GetVector2D() tvector = vector.Copy() tvector.Rotate(-90) # Move to cell position pos = Point2D().SetFrom3D(db.position.Copy()) # Calculate the random point #random.seed() r1 = random.uniform(0, self._gridCellSize) r2 = random.uniform(0, self._width / 2) pos.Move(vector, r1) pos.Move(tvector, -r2) return Point3D(pos.x, pos.y, self._height)
def GetSubPositions(self, center, number, bounding): # Return a list of positions that should be the center of given bounding subdivided number times and centered at center # The subdivision is performed by length # This function is usefull for those battalions that want to be dissolved into smaller ones ret = [] if (number <= 0): return ret parts = (bounding.length / float(number)) vector = self.__GetVector2D() pos = Point2D().SetFrom3D(center) pos.Move(vector, (-bounding.length / 2.0) - (parts / 2.0)) i = 0 while (i < number): pos.Move(vector, parts) ret.append(Point3D(pos.x, pos.y, center.z)) i += 1 return ret
def __GetEndLine3D(self): return Point3D(self._line.p2.x, self._line.p2.y, self._height)
def JoinShape(self, obj, invert=False): # Creates and join current shape with given object's shape # Note the order of objects: "Current wall is going to be joined with given object". This means that only is calculated the ending wall join # The invert flag changes this behaviour (only for towers -> TODO: Also for walls) factory = ConstructionFactory() if obj == None: # None object to join. Constructs a simple rectangular wall shape del self._shape2D[0:len(self._shape2D)] l = self.GetLength() vector = Vector2D() vector.CreateFrom2Points(self.GetStartPosition(), self.GetEndPosition()) tvector = vector.Copy() tvector.Rotate(-90) p = self.GetStartPosition().Copy() p.Move(tvector, self._thickness / 2) self._shape2D.append(p.Copy()) p.Move(vector, l) self._shape2D.append(p.Copy()) p.Move(tvector, -self._thickness) self._shape2D.append(p.Copy()) p.Move(vector, -l) self._shape2D.append(p.Copy()) return else: # Updates the adjacencies if invert: self._adjacentConstructions[0] = obj obj._adjacentConstructions[1] = self else: self._adjacentConstructions[1] = obj obj._adjacentConstructions[0] = self if factory.IsWall(obj): # Calculate the bisector between both walls bisecang = self.GetBisector(obj) # The join point will be along the bisector d = (self._thickness / 2.0) / math.cos( math.radians(bisecang["angle"] / 2.0)) # WARNING: We consider all walls of same thickness p = self.GetEndPosition().Copy() p.Move(bisecang["bisector"], d) self._shape2D[1] = p.Copy() obj._shape2D[0] = p.Copy() p.Move(bisecang["bisector"], -(d * 2.0)) self._shape2D[2] = p.Copy() obj._shape2D[3] = p.Copy() self._adjacentConstructions[1] = obj obj._adjacentConstructions[0] = self elif factory.IsSquaredTower(obj): # Calculate the intersection points of wall shape with tower # We must consider the invert flag. If it is true, the joined part will be the starting wall. Otherwise, the ending wall if invert: v = Vector3D().SetFrom2D(self.GetWallVector()) v.Invert() ray1 = Ray(origin=Point3D().SetFrom2D(self._shape2D[1]), direction=v) ray2 = Ray(origin=Point3D().SetFrom2D(self._shape2D[2]), direction=v) else: v = Vector3D().SetFrom2D(self.GetWallVector()) ray1 = Ray(origin=Point3D().SetFrom2D(self._shape2D[0]), direction=v) ray2 = Ray(origin=Point3D().SetFrom2D(self._shape2D[3]), direction=v) int1 = obj.RecieveImpact(ray1) int2 = obj.RecieveImpact(ray2) if int1 != None: if invert: self._shape2D[0] = Point2D().SetFrom3D(int1) else: self._shape2D[1] = Point2D().SetFrom3D(int1) if int2 != None: if invert: self._shape2D[3] = Point2D().SetFrom3D(int2) else: self._shape2D[2] = Point2D().SetFrom3D(int2) # Reshape the wall axis (and all dependant data). Get the medium points of side shape segments mp1 = Segment2D(self._shape2D[0], self._shape2D[3]).GetMidPoint() mp2 = Segment2D(self._shape2D[1], self._shape2D[2]).GetMidPoint() self.SetPosition(mp1, mp2, reshape=False) elif factory.IsRoundedTower(obj): # Calculate the intersection points of wall shape with tower # We must consider the invert flag. If it is true, the joined part will be the starting wall. Otherwise, the ending wall if invert: v = Vector3D().SetFrom2D(self.GetWallVector()) v.Invert() ray1 = Ray(origin=Point3D().SetFrom2D(self._shape2D[1]), direction=v) ray2 = Ray(origin=Point3D().SetFrom2D(self._shape2D[2]), direction=v) else: v = Vector3D().SetFrom2D(self.GetWallVector()) ray1 = Ray(origin=Point3D().SetFrom2D(self._shape2D[0]), direction=v) ray2 = Ray(origin=Point3D().SetFrom2D(self._shape2D[3]), direction=v) int1 = obj.RecieveImpact(ray1) int2 = obj.RecieveImpact(ray2) if int1 != None: if invert: self._shape2D[0] = Point2D().SetFrom3D(int1) else: self._shape2D[1] = Point2D().SetFrom3D(int1) if int2 != None: if invert: self._shape2D[3] = Point2D().SetFrom3D(int2) else: self._shape2D[2] = Point2D().SetFrom3D(int2) # Reshape the wall axis (and all dependant data). Get the medium points of side shape segments mp1 = Segment2D(self._shape2D[0], self._shape2D[3]).GetMidPoint() mp2 = Segment2D(self._shape2D[1], self._shape2D[2]).GetMidPoint() self.SetPosition(mp1, mp2, reshape=False) elif factory.IsBastion(obj): # Fit the wall to the bastion if invert: self._shape2D[3] = obj.GetEndPosition(exterior=False) self._shape2D[0] = obj.GetEndPosition(exterior=True) else: self._shape2D[1] = obj.GetStartPosition(exterior=True) self._shape2D[2] = obj.GetStartPosition(exterior=False) # Reshape the wall axis (and all dependant data). Get the medium points of side shape segments mp1 = Segment2D(self._shape2D[0], self._shape2D[3]).GetMidPoint() mp2 = Segment2D(self._shape2D[1], self._shape2D[2]).GetMidPoint() self.SetPosition(mp1, mp2, reshape=False)
def GetStartCircle3D(self): p = Point3D() p.x = self.__center.x p.y = self.__center.y p.z = self._height
def GetPosition(self): return Point3D()
def GetWeakestPoint(self): if (len(self.__weakestConstructionList) > 0): return self.__weakestConstructionList[0]["weakPoint"] else: return Point3D()
def CalculateResults(self): # Performs results calculations to extract useful data self.__meanRounds = 0 self.__attackersVictories = 0 self.__defendersVictories = 0 self.__attackersKilled = 0 self.__defendersKilled = 0 del self.__constructionsDefeated["Climbed"][ 0:len(self.__constructionsDefeated["Climbed"])] del self.__constructionsDefeated["Fall"][ 0:len(self.__constructionsDefeated["Fall"])] del self.__constructionsDefeated["SiegeTower"][ 0:len(self.__constructionsDefeated["SiegeTower"])] del self.__weakestConstructionList[0:len(self.__weakestConstructionList )] if (len(self.__resultsList) == 0): Message.Log('No statistics for 0 games', Message.VERBOSE_STATISTICS) return # Gather results constr = {} for r in self.__resultsList: self.__meanRounds += r.GetRounds() if (r.IsWallDefeated()): w = constr.get(r.GetConstruction()) if (w == None): constr[r.GetConstruction()] = { "number": 1, "climbs": [], "falls": [], "siegetowers": [] } else: constr[r.GetConstruction()]["number"] += 1 if (r.IsWallDefeatedByClimbing()): constr[r.GetConstruction()]["climbs"].append( r.GetPosition()) elif (r.IsWallDefeatedByFall()): constr[r.GetConstruction()]["falls"].append(Point3D()) elif (r.IsWallDefeatedBySiegeTower()): constr[r.GetConstruction()]["siegetowers"].append( r.GetPosition()) else: if (r.AttackersWon()): self.__defendersKilled += 1 else: self.__attackersKilled += 1 if (r.AttackersWon()): self.__attackersVictories += 1 self.__meanRounds /= len(self.__resultsList) self.__defendersVictories = len( self.__resultsList) - self.__attackersVictories # Calculate constructions weak points clustering all succeed climbings tmplist = [] for k, v in constr.iteritems(): cclimb = ClusteringKMeans(points=v["climbs"], initialMeans=3) cclimb.execute() weakclimb = cclimb.GetLargestCluster() sclimb = ClusteringKMeans(points=v["siegetowers"], initialMeans=3) sclimb.execute() weaksiegetower = sclimb.GetLargestCluster() if (len(v["climbs"]) > 0): self.__constructionsDefeated["Climbed"].append({ "label": k, "defeats": len(v["climbs"]), "weakPoint": weakclimb }) if (len(v["falls"]) > 0): self.__constructionsDefeated["Fall"].append({ "label": k, "defeats": len(v["falls"]), "weakPoint": Point3D() }) if (len(v["siegetowers"]) > 0): self.__constructionsDefeated["SiegeTower"].append({ "label": k, "defeats": len(v["siegetowers"]), "weakPoint": weaksiegetower }) # Calculate the weakest point in construction wc = {"label": None, "defeats": 0, "weakPoint": Point3D()} wc["label"] = k wc["defeats"] = v["number"] wlst = v["climbs"] wlst.extend(v["siegetowers"]) wclust = ClusteringKMeans(points=wlst, initialMeans=3) wclust.execute() wc["weakPoint"] = wclust.GetLargestCluster() tmplist.append(wc) # Finally, sort the weakest construction list by number of defeats self.__weakestConstructionList = sorted(tmplist, key=lambda k: k['defeats'], reverse=True)
def __GetStartLine3D(self): return Point3D(self._line.p1.x, self._line.p1.y, self._height)