Skip to content

Commit 2043c36

Browse files
jonomonGraylinKim
authored andcommitted
Added creepTracker
1 parent 39c7a40 commit 2043c36

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed

sc2reader/factories/plugins/replay.py

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,238 @@ def APMTracker(replay):
120120

121121
return replay
122122

123+
@plugin
124+
def CreepTracker(replay):
125+
from itertools import izip_longest, dropwhile
126+
from random import random
127+
from math import sqrt, pi
128+
129+
def add_to_list(control_pid,unit_id,unit_location,\
130+
unit_type,event_time, creep_generating_units_list):
131+
length_cgu_list = len(creep_generating_units_list[control_pid])
132+
if length_cgu_list==0:
133+
creep_generating_units_list[control_pid].append([(unit_id, unit_location,unit_type,event_time)])
134+
else:
135+
previous_list = creep_generating_units_list[control_pid][length_cgu_list-1][:]
136+
previous_list.append((unit_id, unit_location,unit_type,event_time))
137+
creep_generating_units_list[control_pid].append(previous_list)
138+
139+
def in_circles(point_x,point_y,cgu_radius):
140+
for cgu in cgu_radius:
141+
circle_x = cgu[0][0]
142+
circle_y = cgu[0][1]
143+
radius = cgu[1]
144+
distance = (circle_x-point_x)**2 + (circle_y-point_y)**2
145+
if distance < (radius*radius):
146+
return 1
147+
return 0
148+
149+
def distance(point1,point2):
150+
distance = (point1[0]-point2[0])**2 + (point1[1]-point2[1])**2
151+
return distance
152+
153+
def calculate_area(cgu_radius):
154+
if len(cgu_radius)==1:
155+
print "Area Calculated",pi*(cgu_radius[0][1]**2)
156+
return pi*(cgu_radius[0][1]**2)
157+
158+
# from cgu_radius get a square which surrounds maximum
159+
# possible area that the creep lies in
160+
max_x = max(cgu_radius, key=lambda x: x[0][0]+x[1])
161+
max_y = max(cgu_radius, key=lambda x: x[0][1]+x[1])
162+
min_x = min(cgu_radius, key=lambda x: x[0][0] - x[1])
163+
min_y = min(cgu_radius, key=lambda x: x[0][1] - x[1])
164+
165+
max_x = max_x[0][0] + max_x[1]
166+
max_y = max_y[0][1] + max_y[1]
167+
min_x = min_x[0][0] - min_x[1]
168+
min_y = min_y[0][1] - min_y[1]
169+
170+
area = 0
171+
for x in range(min_x,max_x):
172+
for y in range(min_y,max_y):
173+
if in_circles(x,y,cgu_radius):
174+
area+=1
175+
return area
176+
177+
178+
def single_linkage_clustering(cgu_points, maxR,labels=0,cgu_length = 0):
179+
inf = -1000
180+
if labels==0:
181+
labels = [0 for x in cgu_points]
182+
cgu_length = len(cgu_points)
183+
if len(cgu_points) ==1:
184+
return [0]
185+
186+
# calculate distance array
187+
distance_array = list()
188+
for i in range (len(cgu_points)):
189+
i_lengths = list()
190+
for j in range(len(cgu_points)):
191+
if i !=j:
192+
if cgu_points[i][0] == inf and cgu_points [j][0] == inf:
193+
i_lengths.append(-inf)
194+
else:
195+
i_lengths.append(distance(cgu_points[i], cgu_points[j]))
196+
197+
distance_array.append(i_lengths)
198+
199+
#Find closest point distance for each point
200+
min_array = map(lambda x:min(x), distance_array)
201+
202+
#combine 2 points with smallest distance
203+
min_distance = min(min_array)
204+
if min_distance < maxR:
205+
point1 = min_array.index(min_distance)
206+
point2 = min_array[point1+1:].index(min_distance)+point1+1
207+
#label each cgu points
208+
current_label = max(labels)+1 if labels[point1] ==0 and\
209+
labels[point2] ==0 else max(labels[point1],labels[point2])
210+
labels[point1] = current_label
211+
labels[point2] = current_label
212+
labels.append(current_label)
213+
214+
new_x = (cgu_points[point1][0] + cgu_points[point2][0])/2
215+
new_y = (cgu_points[point1][1] + cgu_points[point2][1])/2
216+
cgu_points[point1]=(inf,inf)
217+
cgu_points[point2]=(inf,inf)
218+
cgu_points.append((new_x,new_y))
219+
220+
labels = single_linkage_clustering(cgu_points,maxR,labels,cgu_length)
221+
return labels[0:cgu_length]
222+
else:
223+
return_value = labels[0:cgu_length]
224+
return return_value
225+
226+
227+
#Get Map Size
228+
mapinfo = replay.map.archive.read_file('MapInfo')
229+
mapSizeX = ord(mapinfo[16])
230+
mapSizeY = ord(mapinfo[20])
231+
mapSize = mapSizeX * mapSizeX/100
232+
233+
creep_generating_units_list = dict()
234+
235+
for player in replay.players:
236+
player.creep_spread_by_minute = defaultdict(int)
237+
player.max_creep_spread = int()
238+
creep_generating_units_list[player.pid] = list()
239+
try:
240+
replay.tracker_events
241+
except AttributeError:
242+
print "Replay does not have tracker events"
243+
return replay
244+
245+
for tracker_event,game_event in izip_longest(replay.tracker_events,replay.game_events):
246+
247+
# First search things that generate creep
248+
# Tumor, hatcheries, nydus and overlords generating creep
249+
250+
if tracker_event and tracker_event.name == "UnitInitEvent":
251+
units = ["CreepTumor", "Hatchery","Nydus"] # check nydus name
252+
if tracker_event.unit_type_name in units:
253+
add_to_list(tracker_event.control_pid,tracker_event.unit_id,\
254+
(tracker_event.x, tracker_event.y), \
255+
tracker_event.unit_type_name,\
256+
tracker_event.second,\
257+
creep_generating_units_list)
258+
259+
if game_event and game_event.name == "AbilityEvent":
260+
261+
if game_event.ability_name == "GenerateCreep":
262+
add_to_list(game_event.control_pid,game_event.unit_id,\
263+
(game_event.x, game_event.y), \
264+
game_event.unit_type_name,\
265+
game_event.second,\
266+
creep_generating_units_list)
267+
268+
# # Removes creep generating units that were destroyed
269+
if tracker_event and tracker_event.name == "UnitDiedEvent":
270+
for player in creep_generating_units_list:
271+
length_cgu_list = len(creep_generating_units_list[player])
272+
if length_cgu_list ==0:
273+
break
274+
cgu_per_player = creep_generating_units_list[player][length_cgu_list-1]
275+
creep_generating_died = dropwhile(lambda x: x[0] != tracker_event.unit_id, \
276+
cgu_per_player)
277+
for creep_generating_died_unit in creep_generating_died:
278+
279+
cgu_per_player.remove(creep_generating_died_unit)
280+
creep_generating_units_list[player].append(cgu_per_player)
281+
282+
#reduce all events to last event in the minute
283+
last_minute_found = 0
284+
for player in replay.player:
285+
cgu_per_player_new = list()
286+
for cgu_per_player in creep_generating_units_list[player]:
287+
if len(cgu_per_player) ==0:
288+
continue
289+
cgu_last_event_time = cgu_per_player[-1][3]
290+
291+
if (cgu_last_event_time/60)>last_minute_found:
292+
last_minute_found = cgu_last_event_time/60
293+
cgu_per_player_new.append(cgu_per_player)
294+
cgu_per_player = cgu_per_player_new
295+
296+
297+
max_creep_spread=defaultdict()
298+
for player in replay.player:
299+
# convert cg u list into centre of circles and radius
300+
unit_name_to_radius = {'CreepTumor': 15, "Hatchery":17,\
301+
"GenerateCreep": 10, "Nydus": 5 }
302+
303+
max_creep_spread[player] = 0
304+
305+
for index,cgu_per_player in enumerate(creep_generating_units_list[player]):
306+
307+
cgu_radius = map(lambda x: (x[1], unit_name_to_radius[x[2]]),\
308+
cgu_per_player)
309+
cgu_points = map(lambda x: x[0],cgu_radius)
310+
311+
if cgu_points:
312+
labels = single_linkage_clustering(cgu_points,350)
313+
else:
314+
if index != 0:
315+
replay.player[player].creep_spread_by_minute[cgu_last_event_time+1] = 0
316+
continue
317+
318+
area = 0
319+
#if all labels 0 (all separate clusters) calculate it separately
320+
if max(labels) ==0:
321+
for cgu_radi in cgu_radius:
322+
area+= pi * cgu_radi[1]**2
323+
324+
cgu_last_event_time = cgu_per_player[-1][3]/60
325+
replay.player[player].creep_spread_by_minute[cgu_last_event_time] = area/mapSize
326+
continue
327+
328+
count =0
329+
while True:
330+
clusters = filter(lambda x : True if x[0] == count else\
331+
False , zip(labels,cgu_radius) )
332+
333+
cgu_clusters = map(lambda x:x[1], clusters)
334+
if count==0:
335+
for cgu_radi in cgu_clusters:
336+
area+= pi * cgu_radi[1]**2
337+
count+=1
338+
continue
339+
if len(clusters) ==0:
340+
break
341+
count+=1
342+
area += calculate_area(cgu_clusters)
343+
cgu_last_event_time = cgu_per_player[-1][3]/60
344+
replay.player[player].creep_spread_by_minute[cgu_last_event_time] = area/mapSize
345+
346+
if area>max_creep_spread[player]:
347+
max_creep_spread[player] =area
348+
349+
350+
for player in replay.player:
351+
replay.player[player].max_creep_spread = max_creep_spread[player]/mapSize
352+
353+
return replay
354+
123355

124356
@plugin
125357
def SelectionTracker(replay):

0 commit comments

Comments
 (0)