threat evaluation system

threat evaluation system

Here is where ideas can be collected for the skirmish AI in development

Moderators: hoijui, Moderators

Post Reply
joshthewhistler
Posts: 4
Joined: 08 Feb 2010, 16:50

threat evaluation system

Post by joshthewhistler »

I've worked on this for a while. I really don't know how useful this will be to anybody but I might as well post it... It will be most interesting for people with python and pygame installed.

What it needs:
  • a map width and height.
  • a list of enemies.
  • a list of allies.
What it does:
  • Provide a threat graph for the entire map by:
  • Seeding focuspoints across the map in an isometric pattern.
  • Checking the threat level for a circle around each focuspoint.
  • Then using this data to return a threat level for any point on the map by averaging from the nearby focuspoints. It uses an inversely weighted mean: the further the focuspoint is the less it counts.
  • It automatically increases the coverage level in areas with units by creating intermediate focuspoints.
Its disadvantages:
  • It's written in python, to implement it you need to translate to Lua. I wrote it in python because I couldn't find an easy graphics system for Lua to be able to visualise it. I shall translate it to Lua soon.
  • It doesn't delete intermediate focuspoints after units move out of the area so the list of points doesn't decrease again. In practical terms this shouldn't really be a serious disadvantage and it is better than creating all of the intermediate points right away because some of them may never be necessary.
So, I just found out I can't upload .py files. Here is the code, I really recommend copy-pasting into your favourite IDE (I use SciTE):
[edit]Oh no! I do hope your screens are wider than mine, the lines are all messed up. Luckily your screens are very probably wider than mine...[/edit]

Code: Select all

#! /usr/bin/env python
#I don't know why I include the line above but I've seen it done and I've heard it has something to do with running under linux

#This is a python program to test some ideas I had for spring rts ai
#This version uses pygame so that you can view the algorithms in action
#place an ally by right-clicking
#left-clicking places an enemy
#this automatically adds them to the enemies and allies lists
#In the no-graphics version these lists must/can be created by the user
#It quits when the fifth ally is created.
#Joshua Msika
#started: 24/02/2010
#cleaned up and posted: 07/04/2010

#all positions are tuples in format (x,y)

class DGIS(object):
    """A dynamic geographical information system"""
    #DGIS... I had grand ideas for this.
    def __init__(self, mapwidth, mapheight, radius):
        self.width = mapwidth
        self.height = mapheight
        self.radius = radius #the radius the focuspoints will use
        self.points = [] #list of focuspoints
        self.points = self.seedMap(self.width, self.height, self.radius)#see seedMap()
        self.points0 = []#this is the original set of focuspoints and does not change
        for f in self.points:
            self.points0.append(f)
    def seedMap(self,width,height,radius):
        #this returns a list of focus points for the map. It guarantees coverage by 1 focuspoint, sometimes two.
        points = []
        for row in range(0,int(2*height/(3*radius))+2): #there is one row every 1.5 radii
            for column in range(0,int(width/(3**0.5*radius)+2)): #one column every root(3) radii
                position = (column*3**0.5*radius+row%2*3**0.5/2*radius, float(row)*3/2*radius)
                if position[0]> width:
                    #this is messy but puts a line of focuspoints along the far edge of the map.
                    position = (width, float(row)*3/2*radius)
                if position[1] >height:
                    position = (column*3**0.5*radius+row%2*3**0.5/2*radius, height) #Same comment
                newpoint = Focuspoint(position,radius)
                points.append(newpoint)
        return points
    def checkThreat(self,position):
        #uses the focuspoint list to evaluate the threat at a certain location. 
        #It uses all points within radius and gives an inversely weighted average 
        #of their threat values according to distance.
        d= 0
        threat = 0
        flag = True
        for f in self.points:
            if self.distance(f.position, position) <= f.radius:
                distance = self.distance(f.position, position)
                if distance == 0:
                    threat = f.threat #if the position is equal to a focuspoint's position then the threat is obvious.
                    flag = False
                    break
                else:
                    threat += f.threat/distance#this line
                    d += 1/distance            #and this one
        if flag:
            threat = threat/d #and this one compute the weighted average
            return threat
    def checkCoverage(self, position):
        #returns the number of focus points that cover that position
        coverage = 0
        for f in self.points:
            if self.distance(f.position, position) <= self.radius:
                coverage += 1
        return coverage
    def update(self):
        #updates the threat level for all focus points and adds extra focus points
        #in areas with units
        #this means that coverage in areas with units is always 3 and sometimes 4
        uncovered = []
        for a in allies:
            coverage = self.checkCoverage(a.position)
            if coverage < 3:
                uncovered.append(a.position)
        for e in enemies:
            coverage = self.checkCoverage(e.position)
            if coverage < 3:
                uncovered.append(e.position)
        #the following for-loop controls the creation of two new focuspoints equidistant from 
        #each other and from the two closest focuspoints of the original grid
        for u in uncovered:
            #two closest ORIGINAL focus points
            a = (-10,0) #a will be to the left of u
            b = (999999,0) #and b will be to the right of u
            for f in self.points0:
                if f.position[0]<u[0]:
                    if self.distance(f.position, u) < self.distance(a,u):
                        a = f.position #a is overwritten
                if f.position[0]>=u[0]:
                    if self.distance(f.position, u) < self.distance(b,u):
                        b = f.position #b is overwritten
            #the following mathematics can be derived from the euclidean distance formula and
            #the point-slope form of the line that is equidistant from two points
            x1 = a[0]
            y1 = a[1]
            x2 = b[0]
            y2 = b[1]
            if x1==x2:
                slope = 0
            elif y1==y2:
                slope =False
            else:
                slope = float((x1-x2)/(y2-y1))
            xmid = (x1+x2)*0.5
            ymid = (y1+y2)*0.5
            if slope:
                newx = self.radius/2/(slope*slope+1)**0.5+xmid
                newy = slope*(newx-xmid)+ymid
                self.points.append(Focuspoint((newx,newy),self.radius))
                newx = self.radius*-0.5/(slope*slope+1)**0.5+xmid
                newy = slope*(newx-xmid)+ymid
                self.points.append(Focuspoint((newx,newy),self.radius))
            else:
                #in case the points are vertically above each other
                newx = xmid
                newy = y1+0.5*self.radius
                self.points.append(Focuspoint((newx,newy),self.radius))
                newx = xmid
                newy = y1-0.5*self.radius
                self.points.append(Focuspoint((newx,newy),self.radius))
        #updates all focuspoints:
        for f in self.points:
            f.checkThreat()
    def distance(self,point1,point2):
        #calculates the euclidean distance between two points
        distance = ((point1[0]-point2[0])**2+(point1[1]-point2[1])**2)**0.5
        return distance

class Unit(object):
	"""a unit at a certain position, etc."""
	#The Unit class is pretty much self-explanatory.
	def __init__(self, position, target = None, threat = 1):
		self.position = position #a unit's current position
		self.target = target #a unit's target position
		self.threat = threat #a unit's firepower or ability to harm
		self.waypoint = self.position #the position the unit is trying to go to.

class Focuspoint(object):
	#The points used by DGIS to graph the threat level across the whole map
	def __init__(self, position, radius, threat=1):
		self.position = position
		self.radius = radius #the radius in which units are considered for checkThreat()
		self.threat = threat #the threat level at this point
	def checkThreat(self):
		#checks threat within a certain radius of positions. This method could easily be improved/expanded
		threat = 0
		for a in allies:
			distance = DGIS.distance(self.position, a.position)
			if  distance < self.radius:
				threat -= a.threat #subtracts an ally's firepower
		for e in enemies:
			distance = DGIS.distance(self.position, e.position)
			if  distance < self.radius:
				threat += e.threat #adds an enemy's firepower
		self.threat = threat
		return self.threat

#The following code allows viewing of the algorithm in action using pygame:

import pygame

pygame.init()
pygame.display.init()

#Let's define some colours
RED = (255,0,0)
YELLOW = (255,255,0)
GREEN = (0,255,0)
CYAN = (0,255,255)
BLUE = (0,0,255)
PURPLE = (255,0,255)
WHITE = (255,255,255)
BLACK = (0,0,0)

def draw(res):
    for i in range(WIDTH/res):
        for j in range(HEIGHT/res):
            threat = DGIS.checkThreat(((i+0.5)*res,(j+0.5)*res))
            colour = (0+2**threat*32,0+2**threat*32,0+2**threat*32)
            if 0+2**threat*32>255:
                colour = (255,255,255)
            pygame.draw.rect(screen,colour,((i*res,j*res),(i*res+res,j*res+res)))
    for f in DGIS.points:
        position = (int(f.position[0]), int(f.position[1]))
        pygame.draw.circle(screen,BLUE,position,2)
    for a in allies:
        pygame.draw.circle(screen,GREEN,a.position,2)
    for e in enemies:
        pygame.draw.circle(screen,RED,e.position,2)
    return None

def mainloop():
    event = pygame.event.poll()
    screen.fill(BLACK)
    if event.type == 5 and event.dict['button']==1:
        newally = Unit(event.dict['pos'])
        allies.append(newally)
    elif event.type == 5 and event.dict['button']==3:
        newenemy = Unit(event.dict['pos'])
        enemies.append(newenemy)
    elif event.type == 4:
        position = event.dict['pos']
        caption = "Position: "+ str(position)+ "Threat: "+ str(DGIS.checkThreat(position))
        pygame.display.set_caption(caption)
    DGIS.update()
    draw(15)
    pygame.display.flip()
    return None

allies = []#this list
enemies = []#and this one are essential for DGIS to work
WIDTH = 800
HEIGHT = 500
DGIS = DGIS(WIDTH,HEIGHT, 50)

screen =  pygame.display.set_mode((WIDTH,HEIGHT))

while len(allies) < 8:
    mainloop()
    
pygame.display.quit()
pygame.quit()

User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Re: threat evaluation system

Post by hughperkins »

You know, I for one would love to see a Python gateway for AIs. Python is really easy to write stuff in, cross-platform, and very acceptable in the opensource community. Also, the python engine is I think relatively light-weight, and is installed as standard on many mainstream linux distributions.
Post Reply

Return to “AI”