summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2015-08-28 17:27:42 +0200
committerFlorian Jung <flo@windfisch.org>2015-08-28 18:37:47 +0200
commite4b732abd4ea034f75645d333ff5b357d1b612e7 (patch)
tree6d455caf4a92a4df7ac4ada2a8bfe2d62e95fed9
parent024a2e35638436dd36379d86f1619b617c2ecea9 (diff)
track shooting angles and distances
-rw-r--r--gui.py2
-rw-r--r--stats.py93
-rw-r--r--strategy.py1
-rw-r--r--subscriber.py32
4 files changed, 110 insertions, 18 deletions
diff --git a/gui.py b/gui.py
index 83730bf..26b1045 100644
--- a/gui.py
+++ b/gui.py
@@ -211,7 +211,7 @@ def draw_cell(cell):
cx2,cy2 = world_to_win_pt(p2,c.player.center)
cx3,cy3 = world_to_win_pt(p3,c.player.center)
- except AttributeError:
+ except (AttributeError, TypeError):
cx2,cy2=cx,cy
cx3,cy3=cx,cy
diff --git a/stats.py b/stats.py
index 0b460c5..a136ca9 100644
--- a/stats.py
+++ b/stats.py
@@ -4,6 +4,13 @@ import random
from collections import defaultdict
import pickle
from functools import reduce
+import mechanics
+import geometry
+
+def fit_gaussian(l):
+ mean = sum(l) / len(l)
+ stddev = math.sqrt(sum(map(lambda v : (v-mean)**2, l)) / len(l))
+ return mean, stddev
def flatten(l):
return reduce(lambda a,b:a+b, l)
@@ -47,11 +54,11 @@ class Stats:
def __init__(self,c,data=None):
self.c = c
- self.split_countdown = 27*20
+ self.countdown = 27*20
if data == None:
self.data = StatData()
- self.data.version = 2
+ self.data.version = 3
self.data.min_mass = 0
self.data.max_mass = 0
@@ -66,6 +73,9 @@ class Stats:
self.data.size_vs_speed = defaultdict(return_defaultdict_with_zeros)
self.data.size_vs_visible_window = defaultdict(return_defaultdict_with_empty_list)
self.data.mass_vs_visible_window = defaultdict(return_defaultdict_with_empty_list)
+
+ self.data.eject_distlogs = {"virus" : [], "split cell" : [], "ejected mass" : []}
+ self.data.eject_deviations = {"virus" : [], "split cell" : [], "ejected mass" : []}
else:
self.data = data
@@ -93,10 +103,20 @@ class Stats:
return list[-steps:]
def process_frame(self):
- self.split_countdown -= 1
- if (self.split_countdown <= 0):
- self.split_countdown = int(27* (random.random() * 75))
- self.c.send_split()
+ self.countdown -= 1
+ if (self.countdown <= 0):
+ quick_followup = (random.random() < 0.1)
+
+ if quick_followup:
+ self.countdown = 7
+ else:
+ self.countdown = int(27* (random.random() * 15))
+
+ what_to_do = random.random()
+ if what_to_do < 0.2:
+ self.c.send_split()
+ else:
+ self.c.send_shoot()
self.log_pos(self.c.player.center)
self.log_mass(self.c.player.total_mass)
@@ -124,6 +144,60 @@ class Stats:
self.data.size_vs_visible_window[n_own_cells][own_total_size].append((visible_width,visible_height))
self.data.mass_vs_visible_window[n_own_cells][own_total_mass].append((visible_width,visible_height))
+
+
+ # find ejected mass, split cells or viruses that have come to rest
+ for cell in cells:
+ if hasattr(cell,"parent") and cell.parent != None and not cell.calmed_down:
+ # we're only interested in cells with a parent set, because
+ # this also implies that we have tracked them since their
+ # creation.
+ # also, we're only interested in cells that are still flying
+ # as a result of being ejected/split.
+
+ if not cell.is_food and not cell.is_ejected_mass and not cell.is_virus:
+ expected_speed = mechanics.speed(cell.size)
+ celltype = "split cell"
+ elif cell.is_virus:
+ expected_speed = 1
+ celltype = "virus"
+ elif cell.is_ejected_mass:
+ expected_speed = 1
+ celltype = "ejected mass"
+
+
+ if cell.movement.len() < expected_speed * 1.1:
+ print(celltype+" has come to rest, nframes="+str(len(cell.poslog)))
+ cell.calmed_down = True
+ # TODO: speed log
+
+ distance = (cell.spawnpoint - cell.pos).len()
+ distance_from_parent = (cell.parentpos_when_spawned - cell.pos).len()
+
+ self.data.eject_distlogs[celltype] += [(distance, distance_from_parent, cell.parentsize_when_spawned)]
+ print(" flown distance = "+str(distance))
+
+ if len(cell.poslog) == 5:
+ # calculate movement direction from the first 5 samples
+
+ # first check whether they're on a straight line
+ if geometry.is_colinear(cell.poslog) and cell.shoot_vec != None:
+ print(celltype+" direction available!")
+ fly_direction = cell.poslog[-1] - cell.poslog[0]
+ fly_angle = math.atan2(fly_direction.y, fly_direction.x)
+
+ shoot_angle = math.atan2(cell.shoot_vec.y, cell.shoot_vec.x)
+
+
+ deviation = (fly_angle - shoot_angle) % (2*math.pi)
+ if deviation > math.pi: deviation -= 2*math.pi
+ print(" deviation = "+str(deviation*180/math.pi))
+
+ self.data.eject_deviations[celltype] += [deviation]
+
+ else:
+ print(celltype+" did NOT fly in a straight line, ignoring...")
+
def save(self,filename):
pickle.dump(self.data, open(filename,"wb"))
@@ -220,3 +294,10 @@ class Stats:
for ncells in sorted(self.data.mass_vs_visible_window.keys()):
print("\nwith "+str(ncells)+" cells, depending on sum(mass)")
self.analyze_visible_window_helper(self.data.mass_vs_visible_window[ncells], verbose)
+
+ def analyze_deviations(self, celltype):
+ ds = self.data.eject_deviations[celltype]
+ if len(ds) == 0: return
+
+ mean, stddev = fit_gaussian(ds)
+ print(celltype+" eject/split direction deviations: mean = "+str(mean)+", stddev="+str(stddev))
diff --git a/strategy.py b/strategy.py
index 1a57897..1be22cf 100644
--- a/strategy.py
+++ b/strategy.py
@@ -201,7 +201,6 @@ class Strategy:
runaway = True
except:
print("TODO FIXME: need to handle enemy cell which is in our centerpoint!")
- raise
# wall avoidance
if self.c.player.center[0] < self.c.world.top_left[1]+(self.c.player.total_size*2):
diff --git a/subscriber.py b/subscriber.py
index 03a36b0..cedee99 100644
--- a/subscriber.py
+++ b/subscriber.py
@@ -69,7 +69,7 @@ class DummySubscriber:
class CellHistory:
def __init__(self):
- self.poslog = deque(maxlen=10)
+ self.poslog = deque(maxlen=300)
self.stale = False
class OtherPlayer:
@@ -110,7 +110,6 @@ class EnhancingSubscriber(DummySubscriber):
cell.movement = (cell.pos - oldpos)/3
cell.movement_angle = cell.movement.angle()
except (AttributeError, IndexError):
- # no oldpos available
pass
@@ -142,16 +141,15 @@ class EnhancingSubscriber(DummySubscriber):
cell.parent = cell.parent
except:
cell.parent = None
- print("new cell, setting parent = None")
+ cell.calmed_down = True
# clean up obsolete parent references
if cell.parent and cell.parent.cid not in self.c.world.cells:
cell.parent = None
- print("obsolete parent")
# find split cells
+ is_split = False
if not cell.is_food and not cell.is_ejected_mass and not cell.is_virus:
- is_split = False
try:
if cell.parent == None and cell.movement.len() > 2 * mechanics.speed(cell.size):
print("looks like a split!"+str(cell.movement.len() / mechanics.speed(cell.size)))
@@ -162,9 +160,13 @@ class EnhancingSubscriber(DummySubscriber):
if is_split:
history_len = len(cell.poslog)
cell.parent = min(cell.player.cells, key=lambda c : (c.poslog[-history_len] - cell.poslog[-history_len]).len() if c != cell and len(c.poslog) >= history_len else float('inf'))
+ try:
+ cell.shoot_vec = cell.parent.movement.copy()
+ except:
+ cell.shoot_vec = None
+ cell.calmed_down = False
elif cell.is_virus:
- is_split = False
try:
if cell.parent == None and cell.movement.len() > 0:
print("split virus!")
@@ -174,9 +176,10 @@ class EnhancingSubscriber(DummySubscriber):
if is_split:
cell.parent = min(cell.player.cells, key=lambda c : (c.pos - cell.poslog[0]).len() if c != cell else float('inf'))
+ cell.shoot_vec = None # TODO FIXME: use direction of the last ejected blob feed into the mother virus
+ cell.calmed_down = False
elif cell.is_ejected_mass:
- is_split = False
try:
if cell.parent == None and cell.movement.len() > 0:
print("ejected mass!")
@@ -188,8 +191,17 @@ class EnhancingSubscriber(DummySubscriber):
history_len = len(cell.poslog)
try:
cell.parent = min(filter(lambda c : not c.is_ejected_mass and not c.is_food and not c.is_virus and c.color == cell.color, self.c.world.cells.values()), key=lambda c : (c.poslog[-history_len] - cell.poslog[-history_len]).len() if len(c.poslog) >= history_len else float('inf'))
+ try:
+ cell.shoot_vec = cell.parent.movement.copy()
+ except:
+ cell.shoot_vec = None
+ cell.calmed_down = False
except ValueError:
- # if no possible parents are found, min wil raise a ValueError. ignore that.
+ # if no possible parents are found, min will raise a ValueError. ignore that.
pass
-
-
+
+ if is_split:
+ cell.spawnpoint = cell.pos.copy()
+ cell.parentsize_when_spawned = cell.parent.size if cell.parent != None else None
+ cell.parentpos_when_spawned = cell.parent.pos.copy() if cell.parent != None else None
+