From 6f6c61da00b020d51ffe092177a82489dbc2b2ad Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 03:36:20 +0200 Subject: debugging +/- --- main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.py b/main.py index d87eb3c..c8cc341 100644 --- a/main.py +++ b/main.py @@ -25,8 +25,10 @@ for i in range(1,10): # 10 connection attempts try: token = sys.argv[1] addr, *_ = utils.get_party_address(token) + print("using party token") except: addr, token, *_ = utils.find_server() + print("joining random game") # connect c.connect(addr,token) -- cgit v1.2.3 From 65a4820a90799dfd52f64e95e1ac226953e2cbbc Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 03:36:45 +0200 Subject: autorejoin --- main.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/main.py b/main.py index c8cc341..d13c4ea 100644 --- a/main.py +++ b/main.py @@ -48,6 +48,8 @@ gui.set_client(c) # initialize strategy strategy = Strategy(c) +autorespawn_counter = 60 + # main loop while True: c.on_message() @@ -63,3 +65,10 @@ while True: stats.log_pos(c.player.center) stats.log_mass(c.player.total_mass) gui.update() + + if not c.player.is_alive: + if autorespawn_counter == 0: + c.send_respawn() + autorespawn_counter = 60 + else: + autorespawn_counter-=1 -- cgit v1.2.3 From ec5409a1f1467895af7ebed239bcabb7f3dd2a0c Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 03:37:24 +0200 Subject: naive auto-feeding of friends. fixed all teh crashs :) --- strategy.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/strategy.py b/strategy.py index 0d2d8f0..8b806c8 100644 --- a/strategy.py +++ b/strategy.py @@ -3,6 +3,8 @@ from interval_utils import * import gui import random +friendly_players=["Windfisch","windfisch","Cyanide","cyanide"] + class Strategy: def __init__(self, c): self.target = (0,0) @@ -105,8 +107,19 @@ class Strategy: def process_frame(self): runaway = False - my_smallest = min(map(lambda cell : cell.mass, self.c.player.own_cells)) - my_largest = max(map(lambda cell : cell.mass, self.c.player.own_cells)) + my_smallest = min(self.c.player.own_cells, key=lambda cell : cell.mass) + my_largest = max(self.c.player.own_cells, key=lambda cell : cell.mass) + + friendly_cells = list(filter(lambda c : c.name in friendly_players, self.c.world.cells.values())) + if friendly_cells: + friend_to_feed = max(friendly_cells, key=lambda c:c.mass) + if friend_to_feed.mass < 1.25 * my_largest.mass: + print("friend to small") + friend_to_feed = None + if friend_to_feed != None and (self.target_cell != friend_to_feed): + print("now feeding "+friend_to_feed.name) + self.target_cell = friend_to_feed + self.has_target = True # enemy/virus avoidance @@ -115,11 +128,14 @@ class Strategy: relpos = ((cell.pos[0]-self.c.player.center[0]),(cell.pos[1]-self.c.player.center[1])) dist = math.sqrt(relpos[0]**2+relpos[1]**2) - if (not cell.is_virus and dist < ((500+2*cell.size) if cell.mass > 1.25*my_smallest*2 else (300+cell.size)) and cell.mass > 1.25 * my_smallest) or (cell.is_virus and dist < my_largest and cell.mass < my_largest): - angle = math.atan2(relpos[1],relpos[0]) - corridor_halfwidth = math.asin(cell.size / dist) - forbidden_intervals += canonicalize_angle_interval((angle-corridor_halfwidth, angle+corridor_halfwidth)) - runaway = True + if ( (not cell.is_virus and dist < ((500+2*cell.size) if cell.mass > 1.25*my_smallest.mass*2 else (300+cell.size)) and cell.mass > 1.25 * my_smallest.mass) or (cell.is_virus and dist < my_largest.mass and cell.mass < my_largest.mass) ) and not (cell.name in friendly_players): + try: + angle = math.atan2(relpos[1],relpos[0]) + corridor_halfwidth = math.asin(cell.size / dist) + forbidden_intervals += canonicalize_angle_interval((angle-corridor_halfwidth, angle+corridor_halfwidth)) + runaway = True + except: + print("TODO FIXME: need to handle enemy cell which is in our centerpoint!") # wall avoidance if self.c.player.center[0] < self.c.world.top_left[1]+(self.c.player.total_size*2): @@ -154,11 +170,11 @@ class Strategy: for i in forbidden_intervals: gui.draw_arc(self.c.player.center, self.c.player.total_size+10, i, (255,0,255)) - # if however there's no enemy to avoid, chase food or jizz randomly around + # if however there's no enemy to avoid, try to feed a friend. or chase food or jizz randomly around else: if self.target_cell != None: self.target = tuple(self.target_cell.pos) - if self.target_cell not in self.c.world.cells.values() or not self.edible(self.target_cell): + if self.target_cell not in self.c.world.cells.values() or (not self.edible(self.target_cell) and not self.target_cell.name in friendly_players): self.target_cell = None self.has_target = False print("target_cell does not exist any more") @@ -176,7 +192,7 @@ class Strategy: self.has_target = True self.color = (0,0,255) - print("weight: ", self.weight_cell(self.target_cell)) + #print("weight: ", self.weight_cell(self.target_cell)) print("Found food at: " + str(food[0].pos)) else: rx = self.c.player.center[0] + random.randrange(-400, 401) -- cgit v1.2.3 From 58b0b9da0241ff8623581b2cb837eaf34b8f165d Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 18:06:30 +0200 Subject: UI: change behaviour of S key, allow split+W always --- README | 2 +- gui.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README b/README index 57da257..d609439 100644 --- a/README +++ b/README @@ -7,5 +7,5 @@ move mouse = move left click, space = split right click, w = eject some mass r = respawn -s = lock input. cycles through: user lock -> user and bot lock -> bot lock -> no lock +s = lock input. toggle between "user controls" and "bot controls". hold shift for "nobody controls" esc = quit diff --git a/gui.py b/gui.py index 68aa48e..19fffbb 100644 --- a/gui.py +++ b/gui.py @@ -273,10 +273,10 @@ def draw_frame(): pygame.display.quit() if event.type == KEYDOWN: if event.key == K_s: - if not input and bot_input: + if event.mod & KMOD_SHIFT and (input or bot_input): input = False bot_input = False - elif not input and not bot_input: + elif not input and bot_input: input = True bot_input = False else: @@ -291,11 +291,11 @@ def draw_frame(): marker[event.button-1] = win_to_world_pt(event.pos, c.player.center) marker_updated[event.button-1] = True print("set marker "+str(event.button-1)+" to "+str(event.pos)) + if event.type == KEYDOWN: + if event.key == K_w: + c.send_shoot() + if event.key == K_SPACE: + c.send_split() if input: - if event.type == KEYDOWN: - if event.key == K_w: - c.send_shoot() - if event.key == K_SPACE: - c.send_split() if event.type == MOUSEMOTION: c.send_target(*win_to_world_pt(event.pos, c.player.center)) -- cgit v1.2.3 From c2e13a67d969f1208a8b8c127c94a9841c7048d9 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 18:06:59 +0200 Subject: cell motion history --- gui.py | 7 +++++++ main.py | 5 +++-- subscriber.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/gui.py b/gui.py index 19fffbb..440e0ef 100644 --- a/gui.py +++ b/gui.py @@ -142,6 +142,11 @@ def generate_virus(spikes, spike_length, radius, global_coords): def draw_cell(cell): cx,cy = world_to_win_pt(cell.pos,c.player.center) + try: + cx2,cy2 = world_to_win_pt(cell.poslog[-2],c.player.center) + except: + print("wtf, no poslog available?!") + cx2,cy2=cx,cy radius = world_to_win_length(cell.size) if cell.is_virus: @@ -158,6 +163,8 @@ def draw_cell(cell): gfxdraw.aapolygon(screen, polygon2, color) else: color=(int(cell.color[0]*255), int(cell.color[1]*255), int(cell.color[2]*255)) + + gfxdraw.filled_circle(screen, cx2, cy2, radius, (127,127,127)) if not (cell.is_ejected_mass or cell.is_food): gfxdraw.filled_circle(screen, cx, cy, radius, color) diff --git a/main.py b/main.py index d13c4ea..fd75b42 100644 --- a/main.py +++ b/main.py @@ -9,13 +9,14 @@ import time import random import gui import stats -from subscriber import DummySubscriber +from subscriber import EnhancingSubscriber from interval_utils import * from strategy import * # global vars -sub = DummySubscriber() +sub = EnhancingSubscriber() c = client.Client(sub) +sub.set_client(c) stats = stats.Stats() for i in range(1,10): # 10 connection attempts diff --git a/subscriber.py b/subscriber.py index a637e67..1dcccc6 100644 --- a/subscriber.py +++ b/subscriber.py @@ -1,4 +1,5 @@ from log import log +from collections import deque import sys class DummySubscriber: @@ -65,3 +66,33 @@ class DummySubscriber: def on_debug_line(self,x,y): log("debug line") +class CellHistory: + def __init__(self): + self.poslog = deque(maxlen=10) + self.stale = False + +class EnhancingSubscriber(DummySubscriber): + def __init__(self): + self.c = None + self.history = {} + + def set_client(self,c): + self.c = c + + def on_world_update_post(self): + for cid in self.history: + self.history[cid].stale = True + + for cid in self.c.world.cells: + if cid not in self.history: + self.history[cid] = CellHistory() + print("unknown cell") + + self.history[cid].poslog.append(self.c.world.cells[cid].pos.copy()) + self.c.world.cells[cid].poslog = self.history[cid].poslog + print("poslog of size="+str(len(self.history[cid].poslog))) + + self.history[cid].stale = False + + self.history = {k: v for k, v in self.history.items() if v.stale == False} + -- cgit v1.2.3 From 8a44a7c1f11211d56d54c185dc8fdc90e35f221b Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 18:52:36 +0200 Subject: draw the direction where ejected mass would fly --- gui.py | 15 ++++++++++++--- subscriber.py | 10 ++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/gui.py b/gui.py index 440e0ef..02e4a42 100644 --- a/gui.py +++ b/gui.py @@ -6,6 +6,7 @@ from pygame.locals import * import sys import math import time +from agarnet.agarnet.vec import Vec font_fallback = False try: @@ -143,10 +144,17 @@ def generate_virus(spikes, spike_length, radius, global_coords): def draw_cell(cell): cx,cy = world_to_win_pt(cell.pos,c.player.center) try: - cx2,cy2 = world_to_win_pt(cell.poslog[-2],c.player.center) - except: + mov_ang = cell.movement.angle() + p2 = cell.pos + Vec( math.cos(mov_ang + 10*math.pi/180), math.sin(mov_ang + 10*math.pi/180) ) * (cell.size+700) + p3 = cell.pos + Vec( math.cos(mov_ang - 10*math.pi/180), math.sin(mov_ang - 10*math.pi/180) ) * (cell.size+700) + + cx2,cy2 = world_to_win_pt(p2,c.player.center) + cx3,cy3 = world_to_win_pt(p3,c.player.center) + except AttributeError: print("wtf, no poslog available?!") cx2,cy2=cx,cy + cx3,cy3=cx,cy + radius = world_to_win_length(cell.size) if cell.is_virus: @@ -164,9 +172,10 @@ def draw_cell(cell): else: color=(int(cell.color[0]*255), int(cell.color[1]*255), int(cell.color[2]*255)) - gfxdraw.filled_circle(screen, cx2, cy2, radius, (127,127,127)) if not (cell.is_ejected_mass or cell.is_food): + gfxdraw.aapolygon(screen, [(cx,cy),(cx2,cy2),(cx3,cy3),(cx,cy)] ,(255,127,127)) + gfxdraw.filled_circle(screen, cx, cy, radius, color) gfxdraw.aacircle(screen, cx, cy, radius, (0,0,0)) diff --git a/subscriber.py b/subscriber.py index 1dcccc6..feddf04 100644 --- a/subscriber.py +++ b/subscriber.py @@ -95,4 +95,14 @@ class EnhancingSubscriber(DummySubscriber): self.history[cid].stale = False self.history = {k: v for k, v in self.history.items() if v.stale == False} + + for cid in self.c.world.cells: + cell = self.c.world.cells[cid] + try: + oldpos = cell.poslog[-3-1] + cell.movement = (cell.pos - oldpos)/3 + except (AttributeError, IndexError): + # no oldpos available + cell.movement = None + pass -- cgit v1.2.3 From 12557023aec828af6a9a78473273389750d68330 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 22:28:40 +0200 Subject: remove annoying debug output --- gui.py | 1 - subscriber.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/gui.py b/gui.py index 02e4a42..bce2355 100644 --- a/gui.py +++ b/gui.py @@ -151,7 +151,6 @@ 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: - print("wtf, no poslog available?!") cx2,cy2=cx,cy cx3,cy3=cx,cy diff --git a/subscriber.py b/subscriber.py index feddf04..3312cbd 100644 --- a/subscriber.py +++ b/subscriber.py @@ -86,11 +86,9 @@ class EnhancingSubscriber(DummySubscriber): for cid in self.c.world.cells: if cid not in self.history: self.history[cid] = CellHistory() - print("unknown cell") self.history[cid].poslog.append(self.c.world.cells[cid].pos.copy()) self.c.world.cells[cid].poslog = self.history[cid].poslog - print("poslog of size="+str(len(self.history[cid].poslog))) self.history[cid].stale = False -- cgit v1.2.3 From 5dfe8e88c44e23e8b24c42028b3b2456abaa6cef Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 22:29:08 +0200 Subject: store cell.movement_angle --- gui.py | 2 +- subscriber.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gui.py b/gui.py index bce2355..5025f26 100644 --- a/gui.py +++ b/gui.py @@ -144,7 +144,7 @@ def generate_virus(spikes, spike_length, radius, global_coords): def draw_cell(cell): cx,cy = world_to_win_pt(cell.pos,c.player.center) try: - mov_ang = cell.movement.angle() + mov_ang = cell.movement_angle p2 = cell.pos + Vec( math.cos(mov_ang + 10*math.pi/180), math.sin(mov_ang + 10*math.pi/180) ) * (cell.size+700) p3 = cell.pos + Vec( math.cos(mov_ang - 10*math.pi/180), math.sin(mov_ang - 10*math.pi/180) ) * (cell.size+700) diff --git a/subscriber.py b/subscriber.py index 3312cbd..01853a8 100644 --- a/subscriber.py +++ b/subscriber.py @@ -100,7 +100,7 @@ class EnhancingSubscriber(DummySubscriber): try: oldpos = cell.poslog[-3-1] cell.movement = (cell.pos - oldpos)/3 + cell.movement_angle = cell.movement.angle() except (AttributeError, IndexError): # no oldpos available - cell.movement = None pass -- cgit v1.2.3 From 0dd92dbb7f1cc852f5225074908738a8594d49a3 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 22:30:15 +0200 Subject: do not rely on friendly_players (names) but on friendly_cells (cells) --- strategy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/strategy.py b/strategy.py index 8b806c8..bb1fdd8 100644 --- a/strategy.py +++ b/strategy.py @@ -128,7 +128,7 @@ class Strategy: relpos = ((cell.pos[0]-self.c.player.center[0]),(cell.pos[1]-self.c.player.center[1])) dist = math.sqrt(relpos[0]**2+relpos[1]**2) - if ( (not cell.is_virus and dist < ((500+2*cell.size) if cell.mass > 1.25*my_smallest.mass*2 else (300+cell.size)) and cell.mass > 1.25 * my_smallest.mass) or (cell.is_virus and dist < my_largest.mass and cell.mass < my_largest.mass) ) and not (cell.name in friendly_players): + if ( (not cell.is_virus and dist < ((500+2*cell.size) if cell.mass > 1.25*my_smallest.mass*2 else (300+cell.size)) and cell.mass > 1.25 * my_smallest.mass) or (cell.is_virus and dist < my_largest.mass and cell.mass < my_largest.mass) ) and not (cell in friendly_cells): try: angle = math.atan2(relpos[1],relpos[0]) corridor_halfwidth = math.asin(cell.size / dist) @@ -171,10 +171,10 @@ class Strategy: gui.draw_arc(self.c.player.center, self.c.player.total_size+10, i, (255,0,255)) # if however there's no enemy to avoid, try to feed a friend. or chase food or jizz randomly around - else: + else: if self.target_cell != None: self.target = tuple(self.target_cell.pos) - if self.target_cell not in self.c.world.cells.values() or (not self.edible(self.target_cell) and not self.target_cell.name in friendly_players): + if self.target_cell not in self.c.world.cells.values() or (not self.edible(self.target_cell) and not self.target_cell in friendly_cells): self.target_cell = None self.has_target = False print("target_cell does not exist any more") -- cgit v1.2.3 From 1cdfcb0bce30f3debe31ec3c561e5171fda947fd Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 22:30:33 +0200 Subject: more interval util functions --- interval_utils.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/interval_utils.py b/interval_utils.py index 0095c06..7123893 100644 --- a/interval_utils.py +++ b/interval_utils.py @@ -70,13 +70,37 @@ def intervals_intersect(int1_, int2_): return False -def check_cell_in_interval(origin, cell, interval): +def intersection(int1s, int2s): + #expects merged, canonicalized intervals, returns overlap-free canonicalized intervals + + result = [] + + for int1 in int1s: + for int2 in int2s: + if (max(int1[0],int2[0]) <= min(int1[1],int2[1])): + result += [(max(int1[0],int2[0]), min(int1[1],int2[1]))] + + return result + +def interval_area(ints): + result = 0 + for i in merge_intervals(ints): + result += i[1]-i[0] + return result + +def interval_occupied_by_cell(origin, cell): ang = get_point_angle(origin, cell.pos) dist = math.sqrt( (cell.pos[0]-origin[0])**2 + (cell.pos[1]-origin[1])**2 ) - corridor_halfwidth = math.asin(cell.size / dist) + if cell.size >= dist: + corridor_halfwidth = math.pi/2 + else: + corridor_halfwidth = math.asin(cell.size / dist) + + return (ang-corridor_halfwidth, ang+corridor_halfwidth) - return intervals_intersect(interval, (ang-corridor_halfwidth, ang+corridor_halfwidth)) +def check_cell_in_interval(origin, cell, interval): + return intervals_intersect(interval, interval_occupied_by_cell(origin,cell)) def get_cells_in_interval(origin, interval, cells): return list(filter(lambda x: check_point_in_interval(origin, x.pos, interval), cells)) -- cgit v1.2.3 From 1264912f99c6a9298ca2bfda87a60d58ca3bba44 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 22:30:44 +0200 Subject: try to W-feed friends. for testing, treat viruses as friends --- strategy.py | 54 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/strategy.py b/strategy.py index bb1fdd8..67b001e 100644 --- a/strategy.py +++ b/strategy.py @@ -110,17 +110,61 @@ class Strategy: my_smallest = min(self.c.player.own_cells, key=lambda cell : cell.mass) my_largest = max(self.c.player.own_cells, key=lambda cell : cell.mass) - friendly_cells = list(filter(lambda c : c.name in friendly_players, self.c.world.cells.values())) + friendly_cells = list(filter(lambda c : c.is_virus or c.name in friendly_players, self.c.world.cells.values())) if friendly_cells: friend_to_feed = max(friendly_cells, key=lambda c:c.mass) if friend_to_feed.mass < 1.25 * my_largest.mass: - print("friend to small") + print("friend too small") friend_to_feed = None if friend_to_feed != None and (self.target_cell != friend_to_feed): print("now feeding "+friend_to_feed.name) - self.target_cell = friend_to_feed - self.has_target = True - + if friend_to_feed: + self.target_cell = friend_to_feed + self.has_target = True + + # can this cell feed that cell? + # "False" means "No, definitely not" + # "True" means "Maybe" + def can_feed(this, that): + if that.is_food or that.is_ejected_mass: + return False + + relpos = this.pos-that.pos + dist = relpos.len() + if dist == 0 or dist >= 700 + this.size + that.size: + return False + + return check_cell_in_interval(this.pos, that, (this.movement_angle - 10*math.pi/180, this.movement_angle + 10*math.pi/180)) + + + success_rate = 0 + for my_cell in self.c.player.own_cells: + try: + my_cell.movement_angle + except AttributeError: + print("FUUUU") + continue + # check if ejecting mass would feed one friend + possibly_feedable_cells = list(filter(lambda c : can_feed(my_cell, c), self.c.world.cells.values())) + possibly_feedable_cells.sort(key = lambda c : (my_cell.pos - c.pos).len()) + + good_intervals = [] + for feedable in possibly_feedable_cells: + print(feedable.name+" is feedable") + if feedable not in friendly_cells: + break + + good_intervals += canonicalize_angle_interval( interval_occupied_by_cell(my_cell.pos, feedable) ) + + good_intervals = merge_intervals(good_intervals) + area = interval_area( intersection(good_intervals, canonicalize_angle_interval((my_cell.movement_angle - 10*math.pi/180, my_cell.movement_angle + 10*math.pi/180))) ) + success_rate += area / (2*10*math.pi/180) / len(list(self.c.player.own_cells)) + + if success_rate >= 0.5: + print("EJECT") + self.c.send_shoot() + + # enemy/virus avoidance forbidden_intervals = [] -- cgit v1.2.3 From 9eba6bcfc35da321a0895a0c36b972634c64592a Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 24 Aug 2015 23:24:25 +0200 Subject: sexy graphics and saner approaching / not approaching friends --- gui.py | 5 +++++ strategy.py | 29 +++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/gui.py b/gui.py index 5025f26..cf68bc5 100644 --- a/gui.py +++ b/gui.py @@ -61,6 +61,11 @@ def draw_circle(pos, r, color, filled=False, global_coords=True): gfxdraw.circle(screen, pos[0], pos[1], r, color) gfxdraw.aacircle(screen, pos[0], pos[1], r, color) +def hilight_cell(cell, color_inner, color_outer, r=20): + draw_circle(cell.pos, cell.size+r, color_outer, True) + draw_circle(cell.pos, cell.size+r/2, color_inner, True) + draw_cell(cell) + def draw_polygon(polygon, color, filled=False, global_coords=True): if len(polygon) > 2: if global_coords: diff --git a/strategy.py b/strategy.py index 67b001e..3bf7739 100644 --- a/strategy.py +++ b/strategy.py @@ -12,6 +12,7 @@ class Strategy: self.target_cell = None self.color = (0,0,0) self.c = c + self.do_approach_friends = True def get_my_smallest(self): return sorted(self.c.player.own_cells, key = lambda x: x.mass)[0] @@ -111,14 +112,29 @@ class Strategy: my_largest = max(self.c.player.own_cells, key=lambda cell : cell.mass) friendly_cells = list(filter(lambda c : c.is_virus or c.name in friendly_players, self.c.world.cells.values())) + if friendly_cells: + dist_to_friend = min(map(lambda c : (self.c.player.center-c.pos).len() - max(my_largest.size, c.size), friendly_cells)) + else: + dist_to_friend = 99999999 + + if dist_to_friend < 20 or my_largest.mass < 60: + if self.do_approach_friends: print("not approaching friends") + self.do_approach_friends = False + elif dist_to_friend > 200 and my_largest.mass > 60 * 1*16: + if not self.do_approach_friends: print("approaching friends") + self.do_approach_friends = True + + if friendly_cells and self.do_approach_friends: friend_to_feed = max(friendly_cells, key=lambda c:c.mass) if friend_to_feed.mass < 1.25 * my_largest.mass: print("friend too small") friend_to_feed = None - if friend_to_feed != None and (self.target_cell != friend_to_feed): - print("now feeding "+friend_to_feed.name) if friend_to_feed: + gui.hilight_cell(friend_to_feed, (255,255,255),(255,127,127),30) + for c in self.c.player.own_cells: + gui.hilight_cell(c, (255,255,255), (255,127,127), 20) + self.target_cell = friend_to_feed self.has_target = True @@ -126,7 +142,7 @@ class Strategy: # "False" means "No, definitely not" # "True" means "Maybe" def can_feed(this, that): - if that.is_food or that.is_ejected_mass: + if that.is_food or that.is_ejected_mass or that.size < 43: # too small cells cannot eat the ejected mass return False relpos = this.pos-that.pos @@ -150,7 +166,7 @@ class Strategy: good_intervals = [] for feedable in possibly_feedable_cells: - print(feedable.name+" is feedable") + gui.hilight_cell(feedable, (255,192,127), (127,127,255)) if feedable not in friendly_cells: break @@ -172,7 +188,7 @@ class Strategy: relpos = ((cell.pos[0]-self.c.player.center[0]),(cell.pos[1]-self.c.player.center[1])) dist = math.sqrt(relpos[0]**2+relpos[1]**2) - if ( (not cell.is_virus and dist < ((500+2*cell.size) if cell.mass > 1.25*my_smallest.mass*2 else (300+cell.size)) and cell.mass > 1.25 * my_smallest.mass) or (cell.is_virus and dist < my_largest.mass and cell.mass < my_largest.mass) ) and not (cell in friendly_cells): + if ( (not cell.is_virus and dist < ((500+2*cell.size) if cell.mass > 1.25*my_smallest.mass*2 else (300+cell.size)) and cell.mass > 1.25 * my_smallest.mass) or (cell.is_virus and dist < my_largest.mass and cell.mass < my_largest.mass) ) and not (cell in friendly_cells) or (cell in friendly_cells) and dist < cell.size+10: try: angle = math.atan2(relpos[1],relpos[0]) corridor_halfwidth = math.asin(cell.size / dist) @@ -208,7 +224,6 @@ class Strategy: self.target_cell = None self.color = (255,0,0) - print ("Running away: " + str((runaway_x-self.c.player.center[0], runaway_y-self.c.player.center[1]))) # a bit of debugging information for i in forbidden_intervals: @@ -236,8 +251,6 @@ class Strategy: self.has_target = True self.color = (0,0,255) - #print("weight: ", self.weight_cell(self.target_cell)) - print("Found food at: " + str(food[0].pos)) else: rx = self.c.player.center[0] + random.randrange(-400, 401) ry = self.c.player.center[1] + random.randrange(-400, 401) -- cgit v1.2.3 From 8b2cfb34d5bc23d53aaf3676f75a227c8ad51506 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 00:03:59 +0200 Subject: gui.draw_bar() --- gui.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/gui.py b/gui.py index cf68bc5..57b08c5 100644 --- a/gui.py +++ b/gui.py @@ -29,13 +29,38 @@ marker_updated = [True, True, True] screensize=(1280, 800) screen=pygame.display.set_mode(screensize,HWSURFACE|DOUBLEBUF|RESIZABLE) + +def draw_bar(rect, val, thresh=None, min=0, max=1, color=(0,0,0), barcolor=None, exceedcolor=(255,0,0), threshcolor=None): + v = (val-min)/(max-min) + t = (thresh-min)/(max-min) + + if barcolor == None: + barcolor_=color + else: + barcolor_=barcolor + if thresh != None and threshcolor==None: + threshcolor_ = ((128+color[0])//2, (128+color[1])//2, (128+color[2])//2) + else: + threshcolor_ = threshcolor + + for i in range(0, 1 if v= t: + draw_box(((rect[0][0]+2 + (rect[1][0]-4)*t , rect[0][1]+2) , ((rect[1][0]-4)*(v-t) , rect[1][1]-4)), exceedcolor, True, False) + + draw_line((rect[0][0]+2+(rect[1][0]-4)*t, rect[0][1]+1), (rect[0][0]+2+(rect[1][0]-4)*t, rect[0][1]+rect[1][1]-1), threshcolor_, False) + + def draw_line(p1, p2, color, global_coords=True): if global_coords: p1 = world_to_win_pt(p1, c.player.center) p2 = world_to_win_pt(p2, c.player.center) - gfxdraw.line(screen, p1[0], p1[1], p2[0], p2[1], color) + gfxdraw.line(screen, int(p1[0]), int(p1[1]), int(p2[0]), int(p2[1]), color) def draw_box(rect, color, filled=False, global_coords=True): if global_coords: -- cgit v1.2.3 From 9a00624c68cc0606cdd2be5eaf4f5c5658edb02a Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 00:04:10 +0200 Subject: fix stupid typo --- strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strategy.py b/strategy.py index 3bf7739..a7e553e 100644 --- a/strategy.py +++ b/strategy.py @@ -121,7 +121,7 @@ class Strategy: if dist_to_friend < 20 or my_largest.mass < 60: if self.do_approach_friends: print("not approaching friends") self.do_approach_friends = False - elif dist_to_friend > 200 and my_largest.mass > 60 * 1*16: + elif dist_to_friend > 200 and my_largest.mass > 60 + 1*16: if not self.do_approach_friends: print("approaching friends") self.do_approach_friends = True -- cgit v1.2.3 From dc0af643b64619a6898fd0c74be1407e73c0fb76 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 00:04:28 +0200 Subject: sexy graphics --- strategy.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/strategy.py b/strategy.py index a7e553e..d0f8583 100644 --- a/strategy.py +++ b/strategy.py @@ -132,12 +132,14 @@ class Strategy: friend_to_feed = None if friend_to_feed: gui.hilight_cell(friend_to_feed, (255,255,255),(255,127,127),30) - for c in self.c.player.own_cells: - gui.hilight_cell(c, (255,255,255), (255,127,127), 20) self.target_cell = friend_to_feed self.has_target = True + if self.do_approach_friends: + for c in self.c.player.own_cells: + gui.hilight_cell(c, (255,255,255), (255,127,127), 20) + # can this cell feed that cell? # "False" means "No, definitely not" # "True" means "Maybe" @@ -176,8 +178,9 @@ class Strategy: area = interval_area( intersection(good_intervals, canonicalize_angle_interval((my_cell.movement_angle - 10*math.pi/180, my_cell.movement_angle + 10*math.pi/180))) ) success_rate += area / (2*10*math.pi/180) / len(list(self.c.player.own_cells)) - if success_rate >= 0.5: - print("EJECT") + + gui.draw_bar(((100,40),(500,24)), success_rate, thresh=.98, color=(0,0,127)) + if success_rate >= 0.98: self.c.send_shoot() -- cgit v1.2.3 From 831445ee305ffef18504e825646cf8e352c48385 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 00:23:03 +0200 Subject: update friend list, remove viruses --- strategy.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/strategy.py b/strategy.py index d0f8583..6ca383f 100644 --- a/strategy.py +++ b/strategy.py @@ -3,7 +3,9 @@ from interval_utils import * import gui import random -friendly_players=["Windfisch","windfisch","Cyanide","cyanide"] +friendly_players=["Windfisch","windfisch","Cyanide","cyanide"] +\ + ["Midna","Nayru","Farore","Din","Ezelo","Navi","Zelda","Tetra","Link","Ciela","Linebeck","Salia","Epona","Shiek"] +\ + ["Vaati","Ganon","Ganondorf","Ghirahim","Agahnim"] class Strategy: def __init__(self, c): @@ -111,7 +113,7 @@ class Strategy: my_smallest = min(self.c.player.own_cells, key=lambda cell : cell.mass) my_largest = max(self.c.player.own_cells, key=lambda cell : cell.mass) - friendly_cells = list(filter(lambda c : c.is_virus or c.name in friendly_players, self.c.world.cells.values())) + friendly_cells = list(filter(lambda c : c.name in friendly_players, self.c.world.cells.values())) if friendly_cells: dist_to_friend = min(map(lambda c : (self.c.player.center-c.pos).len() - max(my_largest.size, c.size), friendly_cells)) -- cgit v1.2.3 From 86db90367b3afb0d5b3c552d22c729255356028f Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 00:24:33 +0200 Subject: less spam --- strategy.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/strategy.py b/strategy.py index 6ca383f..dbe7cd1 100644 --- a/strategy.py +++ b/strategy.py @@ -162,7 +162,7 @@ class Strategy: try: my_cell.movement_angle except AttributeError: - print("FUUUU") + print("cannot calculate shoot angle, too few backlog") continue # check if ejecting mass would feed one friend possibly_feedable_cells = list(filter(lambda c : can_feed(my_cell, c), self.c.world.cells.values())) @@ -241,7 +241,6 @@ class Strategy: if self.target_cell not in self.c.world.cells.values() or (not self.edible(self.target_cell) and not self.target_cell in friendly_cells): self.target_cell = None self.has_target = False - print("target_cell does not exist any more") elif self.target == tuple(self.c.player.center): self.has_target = False print("Reached random destination") -- cgit v1.2.3 From 066b391e0e3b644353e6bafe10656ea902e06780 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 00:49:21 +0200 Subject: allow specification of nickname --- main.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index fd75b42..146087a 100644 --- a/main.py +++ b/main.py @@ -27,6 +27,11 @@ for i in range(1,10): # 10 connection attempts token = sys.argv[1] addr, *_ = utils.get_party_address(token) print("using party token") + + try: + nick = sys.argv[2] + except: + nick = "test cell pls ignore" except: addr, token, *_ = utils.find_server() print("joining random game") @@ -40,7 +45,7 @@ for i in range(1,10): # 10 connection attempts c.disconnect() -c.player.nick="test cell pls ignore" +c.player.nick=nick # initialize GUI -- cgit v1.2.3 From 8a1591c08f7e55ba6d22d5b78a4cb48d8bc0c8d8 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 00:49:34 +0200 Subject: fix crash when no runaway interval is available --- strategy.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/strategy.py b/strategy.py index dbe7cd1..c570d2d 100644 --- a/strategy.py +++ b/strategy.py @@ -219,8 +219,13 @@ class Strategy: forbidden_intervals = merge_intervals(forbidden_intervals) allowed_intervals = invert_angle_intervals(forbidden_intervals) + + try: + (a,b) = find_largest_angle_interval(allowed_intervals) + except: + print("TODO FIXME: need to handle no runaway direction being available!") + (a,b) = (0,0) - (a,b) = find_largest_angle_interval(allowed_intervals) runaway_angle = (a+b)/2 runaway_x, runaway_y = (self.c.player.center[0]+int(100*math.cos(runaway_angle))), (self.c.player.center[1]+int(100*math.sin(runaway_angle))) -- cgit v1.2.3 From ccdf1206ee664a15cf9f4082ebc8835deafdffba Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 14:03:37 +0200 Subject: readme, game mechanics --- README | 7 ++++--- game_mechanics.txt | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 game_mechanics.txt diff --git a/README b/README index d609439..ad6b58a 100644 --- a/README +++ b/README @@ -3,9 +3,10 @@ prerequisites: python3, pygame and websocket-client git submodule update --init python3 main.py -move mouse = move -left click, space = split -right click, w = eject some mass +space = split +w = eject some mass r = respawn s = lock input. toggle between "user controls" and "bot controls". hold shift for "nobody controls" +move mouse = move +mouse left/mid/right click: set markers (currently unused) esc = quit diff --git a/game_mechanics.txt b/game_mechanics.txt new file mode 100644 index 0000000..1bb5987 --- /dev/null +++ b/game_mechanics.txt @@ -0,0 +1,7 @@ +can eject: if size >= 60 i.e. mass >= 35 +eject makes me lose 16 mass +eject distance is between (600+my.size) and (700+my.size), about 10-15 deg deviation +can eat ejected mass if mass >= 18 i.e. size >= 43 + +cell can eat us, if their size/mass(??) is at least 1.25* our size/mass + -- cgit v1.2.3 From 96ab1a8f44caf4f90148842fd826a8698ce144c5 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 15:12:23 +0200 Subject: fix --- main.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index 146087a..69a9499 100644 --- a/main.py +++ b/main.py @@ -18,6 +18,11 @@ sub = EnhancingSubscriber() c = client.Client(sub) sub.set_client(c) stats = stats.Stats() + +try: + nick = sys.argv[2] +except: + nick = "test cell pls ignore" for i in range(1,10): # 10 connection attempts print("trying to connect, attempt "+str(i)) @@ -28,10 +33,6 @@ for i in range(1,10): # 10 connection attempts addr, *_ = utils.get_party_address(token) print("using party token") - try: - nick = sys.argv[2] - except: - nick = "test cell pls ignore" except: addr, token, *_ = utils.find_server() print("joining random game") -- cgit v1.2.3 From 8386ae0e63313ffc5d0fefebda8451d982679e01 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 17:30:58 +0200 Subject: process.frame() in stats.py, no functional changes --- main.py | 6 +++--- stats.py | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/main.py b/main.py index 69a9499..08793d3 100644 --- a/main.py +++ b/main.py @@ -17,7 +17,7 @@ from strategy import * sub = EnhancingSubscriber() c = client.Client(sub) sub.set_client(c) -stats = stats.Stats() +stats = stats.Stats(c) try: nick = sys.argv[2] @@ -69,8 +69,8 @@ while True: if gui.bot_input: c.send_target(target[0], target[1]) - stats.log_pos(c.player.center) - stats.log_mass(c.player.total_mass) + stats.process_frame() + gui.update() if not c.player.is_alive: diff --git a/stats.py b/stats.py index f850339..9a745ab 100644 --- a/stats.py +++ b/stats.py @@ -1,7 +1,8 @@ import time class Stats: - def __init__(self): + def __init__(self,c): + self.c = c self.min_mass = 0 self.max_mass = 0 self.current_mass = 0 @@ -33,4 +34,8 @@ class Stats: self.cell_defensiveness[cell] = value def get_last_steps(self, list, steps = 10): - return list[-steps:] \ No newline at end of file + return list[-steps:] + + def process_frame(self): + self.log_pos(self.c.player.center) + self.log_mass(self.c.player.total_mass) -- cgit v1.2.3 From 0df1c5f7799fdd63c3cd3fdc92bc9ccc60d1da8f Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 19:49:46 +0200 Subject: clean quit --- gui.py | 6 ++++-- main.py | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gui.py b/gui.py index 57b08c5..895b1ac 100644 --- a/gui.py +++ b/gui.py @@ -8,6 +8,8 @@ import math import time from agarnet.agarnet.vec import Vec +running = True + font_fallback = False try: from pygame import freetype @@ -272,7 +274,7 @@ def draw_markers(): draw_marker(marker[i], colors[i], marker_updated[i]) def draw_frame(): - global screen, movement, zoom, screensize, input, bot_input, marker, marker_updated + global screen, movement, zoom, screensize, input, bot_input, marker, marker_updated, running pygame.event.pump() clock.tick() @@ -328,7 +330,7 @@ def draw_frame(): input = False bot_input = True if event.key == K_ESCAPE: - pygame.quit() + running = False if event.key == K_r: c.send_respawn() if event.type == MOUSEBUTTONDOWN: diff --git a/main.py b/main.py index 08793d3..0cd9b30 100644 --- a/main.py +++ b/main.py @@ -58,7 +58,7 @@ strategy = Strategy(c) autorespawn_counter = 60 # main loop -while True: +while gui.running: c.on_message() gui.draw_frame() @@ -79,3 +79,5 @@ while True: autorespawn_counter = 60 else: autorespawn_counter-=1 + +print("bye") -- cgit v1.2.3 From 5b91b2732ed339a1c2559e06833cc4f1daec01ae Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 19:53:35 +0200 Subject: statistics --- main.py | 2 ++ stats.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/main.py b/main.py index 0cd9b30..c0e9a21 100644 --- a/main.py +++ b/main.py @@ -80,4 +80,6 @@ while gui.running: else: autorespawn_counter-=1 +stats.save("stats.pickle") + print("bye") diff --git a/stats.py b/stats.py index 9a745ab..aed7b42 100644 --- a/stats.py +++ b/stats.py @@ -1,4 +1,6 @@ import time +from collections import defaultdict +import pickle class Stats: def __init__(self,c): @@ -12,6 +14,10 @@ class Stats: self.cell_aggressivity = {} self.cell_split_frequency = {} self.cell_defensiveness = {} + + self.size_vs_speed = defaultdict(lambda : defaultdict(lambda : 0)) + self.size_vs_visible_window = defaultdict(lambda : []) + self.mass_vs_visible_window = defaultdict(lambda : []) def log_mass(self, mass): self.mass_history.append((time.time(), mass)) @@ -39,3 +45,31 @@ class Stats: def process_frame(self): self.log_pos(self.c.player.center) self.log_mass(self.c.player.total_mass) + + cells = self.c.world.cells.values() + own_cells = self.c.player.own_cells + + own_total_size = sum( map(lambda cell : cell.size, own_cells) ) + own_total_mass = sum( map(lambda cell : cell.mass, own_cells) ) + + n = 3 + for cell in filter(lambda cell : not cell.is_food and not cell.is_virus and not cell.is_ejected_mass, cells): + if hasattr(cell,'poslog') and len(cell.poslog) > n+1: + cellspeed = 0 + for i in range(1,n+1): + cellspeed += (cell.poslog[-i] - cell.poslog[-i-1]).len() / n + + cellspeed = int(cellspeed) + self.size_vs_speed[cell.size][cellspeed] += 1 + + visible_width = max( map(lambda cell : cell.pos.x - cell.size, cells) ) - min( map(lambda cell : cell.pos.x + cell.size, cells) ) + visible_height = max( map(lambda cell : cell.pos.y - cell.size, cells) ) - min( map(lambda cell : cell.pos.y + cell.size, cells) ) + + self.size_vs_visible_window[own_total_size].append((visible_width,visible_height)) + self.mass_vs_visible_window[own_total_mass].append((visible_width,visible_height)) + + def save(self,filename): + pickle.dump(self, open(filename,"wb")) + + def load(filename): + return pickle.load(open(filename,"rb")) -- cgit v1.2.3 From e1c27fad9b0cb29d13bceeebf98824a47d26371c Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 21:57:46 +0200 Subject: analyze stats --- stats.py | 135 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 29 deletions(-) diff --git a/stats.py b/stats.py index aed7b42..fec5825 100644 --- a/stats.py +++ b/stats.py @@ -1,43 +1,86 @@ import time from collections import defaultdict import pickle +from functools import reduce + +def flatten(l): + return reduce(lambda a,b:a+b, l) + +def quantile(values, q): + if not isinstance(values, list): + return quantile(flatten(map(lambda x : [x[0]]*x[1], sorted(values.items(),key=lambda x:x[0]))), q) + else: + return values[ int(len(values)*q) ] + +def avg(values): + if isinstance(values, list): + return sum(values)/len(values) + else: + return int(sum(map( lambda x : x[0]*x[1], values.items() )) / sum(map(lambda x : x[1], values.items()))) + +def stddev(values): + a=avg(values) + return avg(list(map(lambda v : (v-a)**2, values))) + +def normalize(values): + a=avg(values) + return [x/a for x in values] + +class StatData(): + pass + +def return_empty_list(): + return [] + +def return_zero(): + return 0 + +def return_defaultdict_with_zeros(): + return defaultdict(return_zero) class Stats: - def __init__(self,c): + def __init__(self,c,data=None): self.c = c - self.min_mass = 0 - self.max_mass = 0 - self.current_mass = 0 - - self.mass_history = [] - self.pos_history = [] - self.cell_aggressivity = {} - self.cell_split_frequency = {} - self.cell_defensiveness = {} - - self.size_vs_speed = defaultdict(lambda : defaultdict(lambda : 0)) - self.size_vs_visible_window = defaultdict(lambda : []) - self.mass_vs_visible_window = defaultdict(lambda : []) + + if data == None: + self.data = StatData() + self.data.version = 1 + + self.data.min_mass = 0 + self.data.max_mass = 0 + self.data.current_mass = 0 + + self.data.mass_history = [] + self.data.pos_history = [] + self.data.cell_aggressivity = {} + self.data.cell_split_frequency = {} + self.data.cell_defensiveness = {} + + self.data.size_vs_speed = defaultdict(return_defaultdict_with_zeros) + self.data.size_vs_visible_window = defaultdict(return_empty_list) + self.data.mass_vs_visible_window = defaultdict(return_empty_list) + else: + self.data = data def log_mass(self, mass): - self.mass_history.append((time.time(), mass)) - self.current_mass = mass - if mass > self.max_mass: - self.max_mass = mass - if mass < self.min_mass: - self.min_mass = mass + self.data.mass_history.append((time.time(), mass)) + self.data.current_mass = mass + if mass > self.data.max_mass: + self.data.max_mass = mass + if mass < self.data.min_mass: + self.data.min_mass = mass def log_pos(self, pos): - self.pos_history.append((time.time(), (pos[0], pos[1]))) + self.data.pos_history.append((time.time(), (pos[0], pos[1]))) def update_cell_aggressivity(self, cell, value): - self.cell_aggressivity[cell] = value + self.data.cell_aggressivity[cell] = value def update_cell_split_frequency(self, cell, value): - self.cell_split_frequency[cell] = value + self.data.cell_split_frequency[cell] = value def update_cell_defensiveness(self, cell, value): - self.cell_defensiveness[cell] = value + self.data.cell_defensiveness[cell] = value def get_last_steps(self, list, steps = 10): return list[-steps:] @@ -60,16 +103,50 @@ class Stats: cellspeed += (cell.poslog[-i] - cell.poslog[-i-1]).len() / n cellspeed = int(cellspeed) - self.size_vs_speed[cell.size][cellspeed] += 1 + self.data.size_vs_speed[cell.size][cellspeed] += 1 visible_width = max( map(lambda cell : cell.pos.x - cell.size, cells) ) - min( map(lambda cell : cell.pos.x + cell.size, cells) ) visible_height = max( map(lambda cell : cell.pos.y - cell.size, cells) ) - min( map(lambda cell : cell.pos.y + cell.size, cells) ) - self.size_vs_visible_window[own_total_size].append((visible_width,visible_height)) - self.mass_vs_visible_window[own_total_mass].append((visible_width,visible_height)) + self.data.size_vs_visible_window[own_total_size].append((visible_width,visible_height)) + self.data.mass_vs_visible_window[own_total_mass].append((visible_width,visible_height)) def save(self,filename): - pickle.dump(self, open(filename,"wb")) + pickle.dump(self.data, open(filename,"wb")) def load(filename): - return pickle.load(open(filename,"rb")) + return Stats(None, pickle.load(open(filename,"rb"))) + + + def analyze_speed(self): + results=[] + for size, values in sorted(self.data.size_vs_speed.items(), key=lambda x : x[0]): + minimum = quantile(values, 0.2) + average = quantile(values, 0.5) + maximum = quantile(values, 0.8) + + results += [(size,maximum,average,minimum,False,False,False,len(values))] + + # mark outliers + for i in range(1, len(results)-1): + for j in range(1,4): + if abs(results[i][j] - results[i-1][j]) > 2 and abs(results[i][j] - results[i+1][j]) > 2: + tmp = list(results[i]) + tmp[j+3] = True + results[i] = tuple(tmp) + + coeff_vs_stddev = [] + for coeff in [x/100 for x in range(10,100,1)]: + products = [] + for size, maximum, average, minimum, maxoutlier, avgoutlier, minoutlier, ndata in results: + if not maxoutlier: + products += [size**coeff * maximum] + + coeff_vs_stddev += [(coeff, avg(products), stddev(normalize(products)))] + + best = min(coeff_vs_stddev, key=lambda v:v[2]) + print("size**"+str(best[0])+" * speed = "+str(best[1]) ) + + print("size\tcalc\tmax\tavg\tmin\t\tndata") + for size, maximum, average, minimum, maxoutlier, avgoutlier, minoutlier, ndata in results: + print(str(size) + ":\t" + "%.1f" % (best[1] / size**best[0]) + "\t" + ("*" if maxoutlier else "") + str(maximum) + "\t" + ("*" if avgoutlier else "") + str(average) + "\t" + ("*" if minoutlier else "") + str(minimum) + "\t\t" + str(ndata)) -- cgit v1.2.3 From 9dcba9467aface38c1bb4f0d1a9a478c3e884f20 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 22:52:33 +0200 Subject: store cellspeed with precision of 0.1 --- stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stats.py b/stats.py index fec5825..be8b547 100644 --- a/stats.py +++ b/stats.py @@ -102,7 +102,7 @@ class Stats: for i in range(1,n+1): cellspeed += (cell.poslog[-i] - cell.poslog[-i-1]).len() / n - cellspeed = int(cellspeed) + cellspeed = int(cellspeed*10)/10 self.data.size_vs_speed[cell.size][cellspeed] += 1 visible_width = max( map(lambda cell : cell.pos.x - cell.size, cells) ) - min( map(lambda cell : cell.pos.x + cell.size, cells) ) -- cgit v1.2.3 From b78d6f097f85aa41f384a0f0922c98c58a22c879 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 23:11:08 +0200 Subject: stats can now be calculated over multiple files. readme. --- README | 3 +++ stats.py | 20 ++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/README b/README index ad6b58a..fa3410e 100644 --- a/README +++ b/README @@ -10,3 +10,6 @@ s = lock input. toggle between "user controls" and "bot controls". hold shift fo move mouse = move mouse left/mid/right click: set markers (currently unused) esc = quit + +the stats.py module automatically creates/overwrites the stats.pickle file (roughly 1MB per 5 minutes currently) +which can be loaded using Stats.load() and analyzed using the Stats.analyze_* functions, or using analyze.py diff --git a/stats.py b/stats.py index be8b547..3856c64 100644 --- a/stats.py +++ b/stats.py @@ -117,6 +117,21 @@ class Stats: def load(filename): return Stats(None, pickle.load(open(filename,"rb"))) + def merge(self, filename): + data2 = pickle.load(open(filename,"rb")) + self.data.min_mass = min(self.data.min_mass, data2.min_mass) + self.data.max_mass = max(self.data.max_mass, data2.max_mass) + + for i in data2.size_vs_visible_window: + self.data.size_vs_visible_window[i] += data2.size_vs_visible_window[i] + for i in data2.mass_vs_visible_window: + self.data.mass_vs_visible_window[i] += data2.mass_vs_visible_window[i] + + for i in data2.size_vs_speed: + for j in data2.size_vs_speed[i]: + self.data.size_vs_speed[i][j] += data2.size_vs_speed[i][j] + + def analyze_speed(self): results=[] @@ -125,7 +140,7 @@ class Stats: average = quantile(values, 0.5) maximum = quantile(values, 0.8) - results += [(size,maximum,average,minimum,False,False,False,len(values))] + results += [(size,maximum,average,minimum,False,False,False,sum(values.values()))] # mark outliers for i in range(1, len(results)-1): @@ -145,8 +160,9 @@ class Stats: coeff_vs_stddev += [(coeff, avg(products), stddev(normalize(products)))] best = min(coeff_vs_stddev, key=lambda v:v[2]) - print("size**"+str(best[0])+" * speed = "+str(best[1]) ) print("size\tcalc\tmax\tavg\tmin\t\tndata") for size, maximum, average, minimum, maxoutlier, avgoutlier, minoutlier, ndata in results: print(str(size) + ":\t" + "%.1f" % (best[1] / size**best[0]) + "\t" + ("*" if maxoutlier else "") + str(maximum) + "\t" + ("*" if avgoutlier else "") + str(average) + "\t" + ("*" if minoutlier else "") + str(minimum) + "\t\t" + str(ndata)) + + print("size**"+str(best[0])+" * speed = "+str(best[1]) ) -- cgit v1.2.3 From fdb391eff010c424ad8cd680d49e1523946e769e Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 23:11:17 +0200 Subject: analyze.py --- analyze.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 analyze.py diff --git a/analyze.py b/analyze.py new file mode 100644 index 0000000..2985ef3 --- /dev/null +++ b/analyze.py @@ -0,0 +1,14 @@ +from stats import * +import sys + +if len(sys.argv) >= 2: + files = sys.argv[1:] +else: + files = ["stats.pickle"] + + +s = Stats.load(files[0]) +for f in files[1:]: + s.merge(f) + +s.analyze_speed() -- cgit v1.2.3 From 6a1f478e2168479f88de293a493ce6509d73f03f Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 25 Aug 2015 23:38:24 +0200 Subject: visible window stuff --- analyze.py | 2 ++ stats.py | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/analyze.py b/analyze.py index 2985ef3..aa2bd9f 100644 --- a/analyze.py +++ b/analyze.py @@ -12,3 +12,5 @@ for f in files[1:]: s.merge(f) s.analyze_speed() +s.analyze_visible_window() + diff --git a/stats.py b/stats.py index 3856c64..24378cb 100644 --- a/stats.py +++ b/stats.py @@ -1,4 +1,5 @@ import time +import math from collections import defaultdict import pickle from functools import reduce @@ -7,13 +8,13 @@ def flatten(l): return reduce(lambda a,b:a+b, l) def quantile(values, q): - if not isinstance(values, list): + if isinstance(values, dict): return quantile(flatten(map(lambda x : [x[0]]*x[1], sorted(values.items(),key=lambda x:x[0]))), q) else: return values[ int(len(values)*q) ] def avg(values): - if isinstance(values, list): + if not isinstance(values, dict): return sum(values)/len(values) else: return int(sum(map( lambda x : x[0]*x[1], values.items() )) / sum(map(lambda x : x[1], values.items()))) @@ -166,3 +167,17 @@ class Stats: print(str(size) + ":\t" + "%.1f" % (best[1] / size**best[0]) + "\t" + ("*" if maxoutlier else "") + str(maximum) + "\t" + ("*" if avgoutlier else "") + str(average) + "\t" + ("*" if minoutlier else "") + str(minimum) + "\t\t" + str(ndata)) print("size**"+str(best[0])+" * speed = "+str(best[1]) ) + + def analyze_visible_window(self): + svw = {} + ratios = [] + for size, rects in sorted(self.data.size_vs_visible_window.items(), key=lambda x:x[0]): + maxwidth = quantile(sorted(map(lambda x:x[0], rects)), 0.95) + maxheight = quantile(sorted(map(lambda x:x[1], rects)), 0.95) + + svw[size] = (maxwidth,maxheight) + ratios += [maxwidth/maxheight] + + print(str(size)+"\t"+str(math.sqrt(maxwidth**2+maxheight**2))) + + print (quantile(sorted(ratios),0.5)) -- cgit v1.2.3 From 0b0d7102b6efc629558a7a42fe869ac8b3f9319e Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 26 Aug 2015 00:12:07 +0200 Subject: find out zoom level w.r.t size --- analyze.py | 1 + stats.py | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/analyze.py b/analyze.py index aa2bd9f..1c864b0 100644 --- a/analyze.py +++ b/analyze.py @@ -12,5 +12,6 @@ for f in files[1:]: s.merge(f) s.analyze_speed() +print("\n" + "-"*40 + "\n") s.analyze_visible_window() diff --git a/stats.py b/stats.py index 24378cb..16910e5 100644 --- a/stats.py +++ b/stats.py @@ -171,6 +171,7 @@ class Stats: def analyze_visible_window(self): svw = {} ratios = [] + print("size\tdiag") for size, rects in sorted(self.data.size_vs_visible_window.items(), key=lambda x:x[0]): maxwidth = quantile(sorted(map(lambda x:x[0], rects)), 0.95) maxheight = quantile(sorted(map(lambda x:x[1], rects)), 0.95) @@ -180,4 +181,18 @@ class Stats: print(str(size)+"\t"+str(math.sqrt(maxwidth**2+maxheight**2))) - print (quantile(sorted(ratios),0.5)) + print ("median ratio = "+str(quantile(sorted(ratios),0.5))) + + coeff_vs_stddev=[] + for coeff in [x/100 for x in range(10,100,1)]: + quotients = [] + for size, rect in svw.items(): + if size != 0: + diag = math.sqrt(rect[0]**2+rect[1]**2) + quotients += [diag / size**coeff] + + coeff_vs_stddev += [(coeff, avg(quotients), stddev(normalize(quotients)))] + + best = min(coeff_vs_stddev, key=lambda v:v[2]) + + print("diag / size**"+str(best[0])+" = "+str(best[1])) -- cgit v1.2.3 From 4f0a25d1605b2e9fca4a668ffd8da9fcf4e5579a Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 26 Aug 2015 00:40:18 +0200 Subject: visible rect / size depending on n_cells --- stats.py | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/stats.py b/stats.py index 16910e5..1d34917 100644 --- a/stats.py +++ b/stats.py @@ -33,6 +33,9 @@ class StatData(): def return_empty_list(): return [] +def return_defaultdict_with_empty_list(): + return defaultdict(return_empty_list) + def return_zero(): return 0 @@ -45,7 +48,7 @@ class Stats: if data == None: self.data = StatData() - self.data.version = 1 + self.data.version = 2 self.data.min_mass = 0 self.data.max_mass = 0 @@ -58,8 +61,8 @@ class Stats: self.data.cell_defensiveness = {} self.data.size_vs_speed = defaultdict(return_defaultdict_with_zeros) - self.data.size_vs_visible_window = defaultdict(return_empty_list) - self.data.mass_vs_visible_window = defaultdict(return_empty_list) + self.data.size_vs_visible_window = defaultdict(return_defaultdict_with_empty_list) + self.data.mass_vs_visible_window = defaultdict(return_defaultdict_with_empty_list) else: self.data = data @@ -91,10 +94,11 @@ class Stats: self.log_mass(self.c.player.total_mass) cells = self.c.world.cells.values() - own_cells = self.c.player.own_cells + own_cells = list(self.c.player.own_cells) own_total_size = sum( map(lambda cell : cell.size, own_cells) ) own_total_mass = sum( map(lambda cell : cell.mass, own_cells) ) + n_own_cells = len(own_cells) n = 3 for cell in filter(lambda cell : not cell.is_food and not cell.is_virus and not cell.is_ejected_mass, cells): @@ -109,8 +113,9 @@ class Stats: visible_width = max( map(lambda cell : cell.pos.x - cell.size, cells) ) - min( map(lambda cell : cell.pos.x + cell.size, cells) ) visible_height = max( map(lambda cell : cell.pos.y - cell.size, cells) ) - min( map(lambda cell : cell.pos.y + cell.size, cells) ) - self.data.size_vs_visible_window[own_total_size].append((visible_width,visible_height)) - self.data.mass_vs_visible_window[own_total_mass].append((visible_width,visible_height)) + print("adding ["+str(n_own_cells)+"]["+str(own_total_size)+"]: ...") + 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)) def save(self,filename): pickle.dump(self.data, open(filename,"wb")) @@ -124,9 +129,11 @@ class Stats: self.data.max_mass = max(self.data.max_mass, data2.max_mass) for i in data2.size_vs_visible_window: - self.data.size_vs_visible_window[i] += data2.size_vs_visible_window[i] + for j in data2.size_vs_visible_window[i]: + self.data.size_vs_visible_window[i][j] += data2.size_vs_visible_window[i][j] for i in data2.mass_vs_visible_window: - self.data.mass_vs_visible_window[i] += data2.mass_vs_visible_window[i] + for j in data2.mass_vs_visible_window[i]: + self.data.mass_vs_visible_window[i][j] += data2.mass_vs_visible_window[i][j] for i in data2.size_vs_speed: for j in data2.size_vs_speed[i]: @@ -168,18 +175,18 @@ class Stats: print("size**"+str(best[0])+" * speed = "+str(best[1]) ) - def analyze_visible_window(self): + def analyze_visible_window_helper(self, foo_vs_visible_window, verbose=False): svw = {} ratios = [] - print("size\tdiag") - for size, rects in sorted(self.data.size_vs_visible_window.items(), key=lambda x:x[0]): + if verbose: print("size\tdiag") + for size, rects in sorted(foo_vs_visible_window.items(), key=lambda x:x[0]): maxwidth = quantile(sorted(map(lambda x:x[0], rects)), 0.95) maxheight = quantile(sorted(map(lambda x:x[1], rects)), 0.95) svw[size] = (maxwidth,maxheight) ratios += [maxwidth/maxheight] - print(str(size)+"\t"+str(math.sqrt(maxwidth**2+maxheight**2))) + if verbose: print(str(size)+"\t"+str(math.sqrt(maxwidth**2+maxheight**2))) print ("median ratio = "+str(quantile(sorted(ratios),0.5))) @@ -196,3 +203,11 @@ class Stats: best = min(coeff_vs_stddev, key=lambda v:v[2]) print("diag / size**"+str(best[0])+" = "+str(best[1])) + + def analyze_visible_window(self): + for ncells in sorted(self.data.size_vs_visible_window.keys()): + print("\nwith "+str(ncells)+" cells, depending on sum(size)") + self.analyze_visible_window_helper(self.data.size_vs_visible_window[ncells]) + 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]) -- cgit v1.2.3 From bea9a124317fef3556c5cabacdc66124b201b08b Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 26 Aug 2015 22:49:06 +0200 Subject: randomly split, for statistic purposes --- analyze.py | 2 +- stats.py | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/analyze.py b/analyze.py index 1c864b0..1720719 100644 --- a/analyze.py +++ b/analyze.py @@ -13,5 +13,5 @@ for f in files[1:]: s.analyze_speed() print("\n" + "-"*40 + "\n") -s.analyze_visible_window() +s.analyze_visible_window(True) diff --git a/stats.py b/stats.py index 1d34917..6744d0b 100644 --- a/stats.py +++ b/stats.py @@ -1,5 +1,6 @@ import time import math +import random from collections import defaultdict import pickle from functools import reduce @@ -46,6 +47,8 @@ class Stats: def __init__(self,c,data=None): self.c = c + self.split_countdown = 27*20 + if data == None: self.data = StatData() self.data.version = 2 @@ -90,6 +93,11 @@ 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.log_pos(self.c.player.center) self.log_mass(self.c.player.total_mass) @@ -113,7 +121,6 @@ class Stats: visible_width = max( map(lambda cell : cell.pos.x - cell.size, cells) ) - min( map(lambda cell : cell.pos.x + cell.size, cells) ) visible_height = max( map(lambda cell : cell.pos.y - cell.size, cells) ) - min( map(lambda cell : cell.pos.y + cell.size, cells) ) - print("adding ["+str(n_own_cells)+"]["+str(own_total_size)+"]: ...") 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)) @@ -180,10 +187,12 @@ class Stats: ratios = [] if verbose: print("size\tdiag") for size, rects in sorted(foo_vs_visible_window.items(), key=lambda x:x[0]): - maxwidth = quantile(sorted(map(lambda x:x[0], rects)), 0.95) - maxheight = quantile(sorted(map(lambda x:x[1], rects)), 0.95) - - svw[size] = (maxwidth,maxheight) + maxwidth = quantile(sorted(map(lambda x:x[0], rects)), 0.75) + maxheight = quantile(sorted(map(lambda x:x[1], rects)), 0.75) + + if (math.sqrt(maxwidth**2+maxheight**2) < 4000): + # TODO FIXME + svw[size] = (maxwidth,maxheight) ratios += [maxwidth/maxheight] if verbose: print(str(size)+"\t"+str(math.sqrt(maxwidth**2+maxheight**2))) @@ -191,7 +200,7 @@ class Stats: print ("median ratio = "+str(quantile(sorted(ratios),0.5))) coeff_vs_stddev=[] - for coeff in [x/100 for x in range(10,100,1)]: + for coeff in [x/100 for x in range(0,100,1)]: quotients = [] for size, rect in svw.items(): if size != 0: @@ -204,10 +213,10 @@ class Stats: print("diag / size**"+str(best[0])+" = "+str(best[1])) - def analyze_visible_window(self): + def analyze_visible_window(self, verbose=False): for ncells in sorted(self.data.size_vs_visible_window.keys()): print("\nwith "+str(ncells)+" cells, depending on sum(size)") - self.analyze_visible_window_helper(self.data.size_vs_visible_window[ncells]) + self.analyze_visible_window_helper(self.data.size_vs_visible_window[ncells], verbose) 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]) + self.analyze_visible_window_helper(self.data.mass_vs_visible_window[ncells], verbose) -- cgit v1.2.3 From 739c6c05fdbd980688b847ac778564a32dbd5d8a Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 26 Aug 2015 22:50:06 +0200 Subject: cell.player attribute --- subscriber.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/subscriber.py b/subscriber.py index 01853a8..b2b6643 100644 --- a/subscriber.py +++ b/subscriber.py @@ -71,6 +71,11 @@ class CellHistory: self.poslog = deque(maxlen=10) self.stale = False +class OtherPlayer: + def __init__(self, playerid): + self.playerid = playerid + self.cells = set() + class EnhancingSubscriber(DummySubscriber): def __init__(self): self.c = None @@ -80,6 +85,8 @@ class EnhancingSubscriber(DummySubscriber): self.c = c def on_world_update_post(self): + + # create and purge poslog history, movement and movement_angle for cid in self.history: self.history[cid].stale = True @@ -104,3 +111,18 @@ class EnhancingSubscriber(DummySubscriber): except (AttributeError, IndexError): # no oldpos available pass + + + # create OtherPlayer entries + otherplayers = {} + for cell in self.c.world.cells.values(): + if not cell.is_food and not cell.is_ejected_mass and not cell.is_virus: + playerid = (cell.name, cell.color) + if playerid not in otherplayers: + otherplayers[playerid] = OtherPlayer(playerid) + + cell.player = otherplayers[playerid] + cell.player.cells.add(cell) + else: + cell.player = None + -- cgit v1.2.3 From b1492078b6b23d2ead2aeddeca3fd0f4f69df0ef Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 26 Aug 2015 22:51:02 +0200 Subject: mechanics.py contains the reverse-engineered formulas for the game mechanics --- mechanics.py | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 mechanics.py diff --git a/mechanics.py b/mechanics.py new file mode 100644 index 0000000..d242493 --- /dev/null +++ b/mechanics.py @@ -0,0 +1,3 @@ +def speed(size): + return 86 / (size**0.45) + -- cgit v1.2.3 From be59b002fb2650bf17f58420fa93b0f8bef74a25 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 26 Aug 2015 22:51:20 +0200 Subject: detect splits and add cell.parent attribute --- subscriber.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/subscriber.py b/subscriber.py index b2b6643..e910087 100644 --- a/subscriber.py +++ b/subscriber.py @@ -1,6 +1,7 @@ from log import log from collections import deque import sys +import mechanics class DummySubscriber: def on_connect_error(self,s): @@ -126,3 +127,31 @@ class EnhancingSubscriber(DummySubscriber): else: cell.player = None + # detect split cells and clean up obsolete parent references + for cell in self.c.world.cells.values(): + if not cell.is_food and not cell.is_ejected_mass and not cell.is_virus: + # create attribute if not already there + try: + cell.parent = cell.parent + except: + cell.parent = None + print("new cell, setting parent = None") + + # clean up obsolete parent references + if cell.parent and cell.parent.cid not in self.c.world.cells: + cell.parent = None + print("obsolete parent") + + + 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))) + is_split = True + except AttributeError: + pass + + if is_split: + history_len = len(cell.poslog) + cell.parent = min(self.c.world.cells.values(), key=lambda c : (c.poslog[-history_len] - cell.poslog[-history_len]).len() if c != cell and len(c.poslog) >= history_len else 999999) -- cgit v1.2.3 From ada18916c2ad68f7f2ac2d69ca51ac2e9a8b2df4 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 26 Aug 2015 22:51:28 +0200 Subject: draw cell.parent --- gui.py | 13 +++++++++++++ main.py | 1 + 2 files changed, 14 insertions(+) diff --git a/gui.py b/gui.py index 895b1ac..ed5c9d3 100644 --- a/gui.py +++ b/gui.py @@ -273,6 +273,19 @@ def draw_markers(): for i in [0, 1, 2]: draw_marker(marker[i], colors[i], marker_updated[i]) +def draw_debug(): + for cell in c.world.cells.values(): + parent = None + try: + parent = cell.parent + except AttributeError: + pass + + if parent != None: + draw_line(cell.pos, parent.pos,(255,0,0)) + draw_circle(parent.pos,3,(255,0,0),True) + + def draw_frame(): global screen, movement, zoom, screensize, input, bot_input, marker, marker_updated, running diff --git a/main.py b/main.py index c0e9a21..d07b6b8 100644 --- a/main.py +++ b/main.py @@ -71,6 +71,7 @@ while gui.running: stats.process_frame() + gui.draw_debug() gui.update() if not c.player.is_alive: -- cgit v1.2.3 From 52a1e369c35eed27841f21aa4efc5bc70f421d3a Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Thu, 27 Aug 2015 00:55:29 +0200 Subject: detect ejects and virussplits, and set cell.parent accordingly --- subscriber.py | 92 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 27 deletions(-) diff --git a/subscriber.py b/subscriber.py index e910087..8fba726 100644 --- a/subscriber.py +++ b/subscriber.py @@ -117,41 +117,79 @@ class EnhancingSubscriber(DummySubscriber): # create OtherPlayer entries otherplayers = {} for cell in self.c.world.cells.values(): + playerid = None if not cell.is_food and not cell.is_ejected_mass and not cell.is_virus: playerid = (cell.name, cell.color) - if playerid not in otherplayers: - otherplayers[playerid] = OtherPlayer(playerid) - - cell.player = otherplayers[playerid] - cell.player.cells.add(cell) + elif cell.is_virus: + playerid = "virus" + elif cell.is_food: + playerid = "food" + elif cell.is_ejected_mass: + playerid = "ejected mass" else: - cell.player = None + playerid = "???" + + if playerid not in otherplayers: + otherplayers[playerid] = OtherPlayer(playerid) + + cell.player = otherplayers[playerid] + cell.player.cells.add(cell) # detect split cells and clean up obsolete parent references for cell in self.c.world.cells.values(): - if not cell.is_food and not cell.is_ejected_mass and not cell.is_virus: - # create attribute if not already there - try: - cell.parent = cell.parent - except: - cell.parent = None - print("new cell, setting parent = None") + # create attribute if not already there + try: + cell.parent = cell.parent + except: + cell.parent = None + print("new cell, setting parent = None") - # clean up obsolete parent references - if cell.parent and cell.parent.cid not in self.c.world.cells: - cell.parent = None - print("obsolete parent") + # 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 + 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))) + is_split = True + except AttributeError: + pass + + 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 999999) + + elif cell.is_virus: + is_split = False + try: + if cell.parent == None and cell.movement.len() > 0: + print("split virus!") + is_split = True + except AttributeError: + pass + + if is_split: + cell.parent = min(cell.player.cells, key=lambda c : (c.pos - cell.poslog[0]).len() if c != cell else 999999) - if not cell.is_food and not cell.is_ejected_mass and not cell.is_virus: - is_split = False + elif cell.is_ejected_mass: + is_split = False + try: + if cell.parent == None and cell.movement.len() > 0: + print("ejected mass!") + is_split = True + except AttributeError: + pass + + if is_split: + history_len = len(cell.poslog) 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))) - is_split = True - except AttributeError: + 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 999999) + except ValueError: + # if no possible parents are found, min wil raise a ValueError. ignore that. pass - - if is_split: - history_len = len(cell.poslog) - cell.parent = min(self.c.world.cells.values(), key=lambda c : (c.poslog[-history_len] - cell.poslog[-history_len]).len() if c != cell and len(c.poslog) >= history_len else 999999) + + -- cgit v1.2.3 From a973a8986191a7a492a18a8f52d33bce9b821292 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Thu, 27 Aug 2015 01:28:30 +0200 Subject: s/99999/float(inf)/g --- strategy.py | 2 +- subscriber.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/strategy.py b/strategy.py index c570d2d..2ea84e2 100644 --- a/strategy.py +++ b/strategy.py @@ -118,7 +118,7 @@ class Strategy: if friendly_cells: dist_to_friend = min(map(lambda c : (self.c.player.center-c.pos).len() - max(my_largest.size, c.size), friendly_cells)) else: - dist_to_friend = 99999999 + dist_to_friend = float('inf') if dist_to_friend < 20 or my_largest.mass < 60: if self.do_approach_friends: print("not approaching friends") diff --git a/subscriber.py b/subscriber.py index 8fba726..03a36b0 100644 --- a/subscriber.py +++ b/subscriber.py @@ -161,7 +161,7 @@ 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 999999) + 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')) elif cell.is_virus: is_split = False @@ -173,7 +173,7 @@ class EnhancingSubscriber(DummySubscriber): pass if is_split: - cell.parent = min(cell.player.cells, key=lambda c : (c.pos - cell.poslog[0]).len() if c != cell else 999999) + cell.parent = min(cell.player.cells, key=lambda c : (c.pos - cell.poslog[0]).len() if c != cell else float('inf')) elif cell.is_ejected_mass: is_split = False @@ -187,7 +187,7 @@ class EnhancingSubscriber(DummySubscriber): if is_split: 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 999999) + 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')) except ValueError: # if no possible parents are found, min wil raise a ValueError. ignore that. pass -- cgit v1.2.3 From ea4515d0516dc3f0bd20428f6d032714ca5ffdea Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Thu, 27 Aug 2015 21:05:22 +0200 Subject: reverse engineered zoom level --- reversing_game_mechanics/zoomlevel/README | 30 ++ reversing_game_mechanics/zoomlevel/filter_data.py | 10 + reversing_game_mechanics/zoomlevel/fit.log | 46 +++ reversing_game_mechanics/zoomlevel/stats.pickle.xz | Bin 0 -> 581852 bytes reversing_game_mechanics/zoomlevel/win.mass.1 | 116 ++++++ reversing_game_mechanics/zoomlevel/win.mass.2 | 455 +++++++++++++++++++++ reversing_game_mechanics/zoomlevel/win.mass.3 | 126 ++++++ reversing_game_mechanics/zoomlevel/win.mass.4 | 130 ++++++ reversing_game_mechanics/zoomlevel/win.mass.5 | 8 + reversing_game_mechanics/zoomlevel/win.mass.6 | 4 + .../zoomlevel/win.mass.gnuplot | 9 + reversing_game_mechanics/zoomlevel/win.size.1 | 116 ++++++ reversing_game_mechanics/zoomlevel/win.size.2 | 150 +++++++ reversing_game_mechanics/zoomlevel/win.size.3 | 69 ++++ reversing_game_mechanics/zoomlevel/win.size.4 | 77 ++++ reversing_game_mechanics/zoomlevel/win.size.5 | 8 + reversing_game_mechanics/zoomlevel/win.size.6 | 4 + reversing_game_mechanics/zoomlevel/win.size.all | 424 +++++++++++++++++++ .../zoomlevel/win.size.all.filtered | 227 ++++++++++ .../zoomlevel/win.size.gnuplot | 16 + stats.py | 4 +- 21 files changed, 2027 insertions(+), 2 deletions(-) create mode 100644 reversing_game_mechanics/zoomlevel/README create mode 100644 reversing_game_mechanics/zoomlevel/filter_data.py create mode 100644 reversing_game_mechanics/zoomlevel/fit.log create mode 100644 reversing_game_mechanics/zoomlevel/stats.pickle.xz create mode 100644 reversing_game_mechanics/zoomlevel/win.mass.1 create mode 100644 reversing_game_mechanics/zoomlevel/win.mass.2 create mode 100644 reversing_game_mechanics/zoomlevel/win.mass.3 create mode 100644 reversing_game_mechanics/zoomlevel/win.mass.4 create mode 100644 reversing_game_mechanics/zoomlevel/win.mass.5 create mode 100644 reversing_game_mechanics/zoomlevel/win.mass.6 create mode 100644 reversing_game_mechanics/zoomlevel/win.mass.gnuplot create mode 100644 reversing_game_mechanics/zoomlevel/win.size.1 create mode 100644 reversing_game_mechanics/zoomlevel/win.size.2 create mode 100644 reversing_game_mechanics/zoomlevel/win.size.3 create mode 100644 reversing_game_mechanics/zoomlevel/win.size.4 create mode 100644 reversing_game_mechanics/zoomlevel/win.size.5 create mode 100644 reversing_game_mechanics/zoomlevel/win.size.6 create mode 100644 reversing_game_mechanics/zoomlevel/win.size.all create mode 100644 reversing_game_mechanics/zoomlevel/win.size.all.filtered create mode 100644 reversing_game_mechanics/zoomlevel/win.size.gnuplot diff --git a/reversing_game_mechanics/zoomlevel/README b/reversing_game_mechanics/zoomlevel/README new file mode 100644 index 0000000..72cd14d --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/README @@ -0,0 +1,30 @@ +The goal is to find out the formula to calculate the appropriate zoom level, +or equivalent: to calculate the size of the world viewport depending on, well, +dunno. + +Data collected using bea9a124317, on 2015-08-25 *iirc*. (-> stats.pickle.xz) + +Data analyzed using a973a898619, with: + + python analyze.py stats.pickle > temp + +then manually, create win.{size,mass}.{1,2,3,4,5,6} by cutting the +analyze.py output into pieces (depending on number of cells). + +view with + + gnuplot win.{size,mass}.gnuplot + +the gray lines in win.size.gnuplot denote the filtering conditions of +filter_data.py + +Then merge and filter the data using + + cat win.size.[123456] | python filter_data.py > win.size.all.filtered + +win.size.gnuplot will automatically fit a "a * size**b" - like function. + +Result: visible diagonal = 369.399 * sum(sizes)**0.431776 + +Also, analyze.py tells us that the viewport ratio is 1.7 : 1 + diff --git a/reversing_game_mechanics/zoomlevel/filter_data.py b/reversing_game_mechanics/zoomlevel/filter_data.py new file mode 100644 index 0000000..e801d78 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/filter_data.py @@ -0,0 +1,10 @@ +import sys + +for line in sys.stdin: + line = line.split() + size, diag = int(line[0]), float(line[1]) + upper = size**0.4 * 460 + 50 + lower = size**0.407 * 460 - 400 + if lower < diag and diag < upper: + print(str(size) + "\t" + str(diag) + "\t\t" + line[2]) + diff --git a/reversing_game_mechanics/zoomlevel/fit.log b/reversing_game_mechanics/zoomlevel/fit.log new file mode 100644 index 0000000..10e4639 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/fit.log @@ -0,0 +1,46 @@ + + +******************************************************************************* +Thu Aug 27 21:04:27 2015 + + +FIT: data read from "win.size.all.filtered" using 1:2 + format = x:z + #datapoints = 227 + residuals are weighted equally (unit weight) + +function used for fitting: f(x) +fitted parameters initialized with current variable values + + + + Iteration 0 + WSSR : 1.99006e+09 delta(WSSR)/WSSR : 0 + delta(WSSR) : 0 limit for stopping : 1e-05 + lambda : 543.709 + +initial set of free parameter values + +a = 1 +b = 1 + +After 187 iterations the fit converged. +final sum of squares of residuals : 316175 +rel. change during last iteration : -9.20903e-11 + +degrees of freedom (FIT_NDF) : 225 +rms of residuals (FIT_STDFIT) = sqrt(WSSR/ndf) : 37.4863 +variance of residuals (reduced chisquare) = WSSR/ndf : 1405.22 + +Final set of parameters Asymptotic Standard Error +======================= ========================== + +a = 369.399 +/- 4.401 (1.191%) +b = 0.431776 +/- 0.002383 (0.5519%) + + +correlation matrix of the fit parameters: + + a b +a 1.000 +b -0.998 1.000 diff --git a/reversing_game_mechanics/zoomlevel/stats.pickle.xz b/reversing_game_mechanics/zoomlevel/stats.pickle.xz new file mode 100644 index 0000000..c915674 Binary files /dev/null and b/reversing_game_mechanics/zoomlevel/stats.pickle.xz differ diff --git a/reversing_game_mechanics/zoomlevel/win.mass.1 b/reversing_game_mechanics/zoomlevel/win.mass.1 new file mode 100644 index 0000000..1bac0fb --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.mass.1 @@ -0,0 +1,116 @@ +0.0 9957.478596512272 16 +24.01 2120.5192760265113 245 +25.0 1969.829688069504 88 +26.01 1907.5106814904077 196 +27.04 1652.2645066695586 49 +28.09 1860.7818249327352 96 +29.16 1851.8933554608375 58 +30.25 1468.638825579659 70 +31.36 2251.943604977709 106 +32.49 2004.575765592311 166 +33.64 2109.127781809343 362 +34.81 2126.4564420650613 137 +36.0 1994.1740144731602 91 +37.21 2173.5730951592127 58 +38.44 1940.5630626186824 52 +39.69 2232.8013794334684 39 +40.96 2133.3471353720192 71 +42.25 2239.5713875650404 100 +43.56 2259.5827048373335 868 +44.89 2240.224319125208 818 +46.24 2307.553032976707 443 +47.61 2226.5634956138124 579 +49.0 2356.425258734085 336 +50.41 2293.2538019155227 397 +51.84 2249.2098612623945 273 +53.29 2331.4519081465096 451 +54.76 2392.639755583778 300 +56.25 2404.2996901384818 277 +57.76 2403.8011565019265 161 +59.29 2357.5313359529287 262 +60.84 2377.4242364374095 157 +62.41 2339.8472172344927 145 +64.0 2438.0258407162137 228 +65.61 2488.3331770484433 301 +67.24 2489.7003835803216 352 +68.89 2499.0544211761376 291 +70.56 2455.6426857342253 304 +72.25 2498.9455776386967 154 +73.96 2378.6727391551785 346 +75.69 2474.5797623030867 702 +77.44 2366.7634017788937 727 +79.21 2442.546417163858 373 +81.0 2515.553616999646 238 +82.81 2614.3163542310635 207 +84.64 2594.101771326638 66 +86.49 2544.643000501249 67 +88.36 2651.225377066235 95 +90.25 2681.96290056369 148 +92.16 2685.0344504307577 170 +94.09 2679.5546271722096 426 +96.04 2693.4938277263605 569 +98.01 2726.821592990638 54 +100.0 2696.036349903317 53 +102.01 2704.8558187082726 56 +104.04 2754.743726737571 88 +106.09 2719.114010114324 180 +108.16 2791.1581825471662 122 +110.25 2794.8023185907086 84 +112.36 2803.209767391659 133 +114.49 2805.824121358999 90 +116.64 2796.2517769328283 250 +118.81 2803.5384784232942 261 +121.0 2837.5144052497776 142 +123.21 2835.092414719492 107 +125.44 2846.737255174773 63 +127.69 2877.452345391666 63 +129.96 2851.5078467365297 53 +132.25 2780.2778638114573 113 +134.56 2891.1260781916794 242 +136.89 2870.733878296628 69 +139.24 2892.3390188565377 88 +141.61 2730.286798122131 145 +144.0 2715.363695713707 389 +146.41 2238.8311682661556 281 +148.84 2913.41998345587 61 +151.29 2955.795155283938 28 +153.76 2385.1079640133694 322 +156.25 3029.202205201891 67 +158.76 3015.162516349658 39 +161.29 3024.4353191959653 64 +163.84 3046.6238691377707 139 +166.41 3020.514029101669 40 +169.0 3015.3225366451265 112 +171.61 3021.6586504765887 92 +174.24 3040.8763539479864 73 +176.89 3065.0941257977706 58 +179.56 2976.10500486794 66 +182.25 3026.624522467232 98 +184.96 3013.2540550043236 84 +187.69 2927.263910206936 80 +190.44 2981.869380103696 80 +193.21 2977.177354475208 52 +196.0 3049.6730972351775 42 +198.81 2354.0403564934904 65 +201.64 2332.625130620006 4 +219.04 3144.616033794905 7 +222.01 3228.400223020684 11 +225.0 3220.1863300125974 71 +228.01 3248.3468103021264 119 +231.04 3253.712494981694 66 +234.09 3238.846245192877 57 +237.16 3176.819950831334 43 +240.25 3301.4617974467005 36 +243.36 3296.8477368541 132 +246.49 3316.3596005258537 113 +249.64 3286.2537942161434 155 +252.81 3083.007946794818 110 +256.0 2909.176000175995 64 +259.21 2641.6837433727756 35 +262.44 2646.5972492995606 65 +265.69 2727.742106578259 49 +268.96 2692.4384858339845 44 +272.25 2498.7140692764347 49 +275.56 2352.3938870860893 36 +278.89 2375.1743093928917 57 +282.24 2304.796954180563 121 diff --git a/reversing_game_mechanics/zoomlevel/win.mass.2 b/reversing_game_mechanics/zoomlevel/win.mass.2 new file mode 100644 index 0000000..8c08b58 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.mass.2 @@ -0,0 +1,455 @@ +40.5 2459.633306003153 36 +40.96 7513.947364734464 1 +41.41 2471.8181567421175 53 +42.34 2602.3854441646417 92 +43.25 2635.398451847462 1 +43.29 2641.4407053727327 15 +43.56 8967.320224013414 2 +44.18 2311.2580989582275 2 +44.2 2693.2903668189956 8 +44.260000000000005 2490.116463139827 12 +45.129999999999995 2369.7818464997995 3 +45.17 2718.7594597536577 30 +45.25 2628.344345781199 17 +46.08 2604.0188171363125 7 +46.1 2714.2109350601327 145 +46.16 2705.3711390491326 30 +46.24 9047.885167264227 3 +46.260000000000005 2529.635546872316 4 +47.05 2559.953905835025 100 +47.09 2748.116627801666 7 +47.29 2672.3012554725187 14 +48.04 2696.738771182704 64 +48.2 2656.4521452493736 2 +49.010000000000005 2747.4096891435756 35 +49.05 1728.9814920929605 28 +49.129999999999995 2674.728023556788 33 +50.0 2718.0345840331024 25 +50.02 1517.5836056046467 115 +50.18 2718.969290006785 29 +50.41 5962.59423405618 1 +51.010000000000005 2762.8052772499186 111 +51.25 2680.7913010900347 24 +52.02 2694.0736812492714 74 +52.04 2728.1513887612614 26 +52.2 2111.7618236912986 65 +52.34 2760.7872065771385 4 +53.05 2689.30344141378 18 +53.09 2777.4263266556686 37 +53.29 2745.1777720213313 68 +54.08 2724.0163362212056 132 +54.1 2821.2488369514663 28 +54.16 2788.0634856473407 51 +54.4 2800.803456153252 243 +54.76 9453.725720582335 1 +55.129999999999995 2814.639586163742 45 +55.17 2818.2379246614364 28 +55.25 2750.93911237599 213 +55.370000000000005 2803.9293857014304 140 +55.53 2788.3961339809666 16 +56.18 2337.0556262100395 51 +56.2 2843.388295678239 34 +56.25 9562.746467411964 1 +56.260000000000005 2824.395333518309 23 +56.36 2756.9746099665117 22 +56.68 2844.9411241711136 10 +57.25 2762.5328957317415 12 +57.29 2829.027394706527 12 +57.370000000000005 2757.496328193385 54 +57.49 2056.103110254931 16 +57.650000000000006 2840.9859204156573 76 +58.34 2798.28965620073 189 +58.5 2573.206948537175 148 +58.82000000000001 2401.801199100375 7 +59.41 2654.4522975559385 20 +59.45 2790.700270541428 8 +59.53 2643.41162137114 5 +59.650000000000006 2746.3783424721364 20 +59.81 2307.9033775268845 17 +60.5 2822.01009920234 2 +60.519999999999996 2569.880347409194 21 +60.68 2517.190894628375 44 +60.82000000000001 2588.53163009456 46 +60.84 4983.02087091756 1 +61.61 2886.1119174418723 20 +61.650000000000006 2569.880347409194 15 +61.85 2246.855580583674 57 +62.010000000000005 2406.397514958823 14 +62.120000000000005 2831.1287501630864 138 +62.72 2905.0335626288384 16 +62.8 2513.3963077875324 18 +63.04 1903.5934439895511 3 +63.05 2840.752893160544 44 +63.22 2224.2942701000693 34 +63.7 2887.0635600900787 158 +63.81 2721.133771059409 9 +63.85 2906.4015551881334 10 +63.97 2513.3963077875324 8 +64.0 2783.724483493293 31 +64.25 2190.683226758264 40 +64.45 2511.4816344142355 32 +64.97 2819.3029280302603 91 +65.0 2905.691828119424 50 +65.16 2769.544727929123 26 +65.3 2769.2159540201988 110 +65.7 2169.302652927894 1 +66.13 2917.1830590485747 32 +66.17 1978.7786637216402 36 +66.37 2866.9461104108673 26 +66.53 2828.3638379812455 176 +66.97 2169.302652927894 2 +67.28 2914.5826459374935 4 +67.30000000000001 1456.4751971798216 33 +67.6 2892.723630075988 18 +68.26 2169.302652927894 1 +68.45 2870.029442357691 68 +68.49000000000001 1493.238427043719 9 +68.56 3071.149133467797 1 +68.85 2876.960201323612 40 +68.89 8841.674502038626 2 +69.62 2759.3203873417815 37 +69.64 2934.570667065286 37 +69.7 1503.1999201703013 20 +70.12 2944.063178669914 15 +70.56 6246.4982190023875 1 +70.81 2861.632051819381 66 +70.85 2948.546930269213 16 +70.93 1951.1483798009826 158 +71.21000000000001 2883.3539498299547 18 +72.0 2895.3979001166663 37 +72.02000000000001 2944.6481963046112 6 +72.08 2900.384802056444 30 +72.18 2046.8927670984624 2 +72.32 2937.0192372539886 65 +73.21000000000001 2890.895017118401 34 +73.25 2878.285079695894 36 +73.45 2660.3768530041 49 +74.42 2244.9518925803286 5 +74.44 2922.8884686214083 47 +74.6 2709.7276615925816 7 +74.74000000000001 2194.8769897194693 16 +75.65 2959.984628338465 37 +75.69 2994.2386344444894 15 +75.77000000000001 2779.7426139842514 10 +76.05000000000001 2211.8340805765697 4 +76.88 2980.0191274553927 13 +76.9 2640.6423460968736 21 +76.96000000000001 3009.2705096085997 39 +77.12 2918.4278301852864 123 +77.38 2188.1373357264392 6 +77.6 2235.5270072177614 9 +78.00999999999999 2934.982112381607 84 +78.13 2953.3900859859336 45 +78.17 2975.29695996887 29 +78.73 2162.7568055609026 8 +78.97 2329.121937555009 16 +79.21 9939.87610586772 1 +79.38 2913.7070889161114 56 +79.4 3010.1975018260846 33 +79.46000000000001 2199.218497557712 8 +79.53999999999999 2982.9921220144047 45 +80.1 2333.552227827781 6 +80.45 2793.836072499602 9 +80.65 2684.162811753415 43 +80.69 2939.1537897837193 6 +81.25 2526.8612941750484 23 +81.92 3014.607768848213 4 +81.94 2141.8881856903736 105 +82.0 2930.1754213698537 36 +82.42 2628.9505510754666 21 +82.81 6944.246107389916 1 +82.93 2891.7330443870505 17 +83.21000000000001 2881.0282886497316 60 +83.25 2973.785466371103 36 +83.3 2722.2448457109804 21 +83.81 2954.6356797412436 40 +83.88 2832.668000313485 2 +84.5 3021.231536972961 13 +84.52000000000001 2897.546720934798 92 +84.58 3001.166606504877 12 +84.85000000000001 2906.164654660847 113 +85.0 3019.600139091267 2 +85.00999999999999 2457.3501988931084 1 +85.81 3025.457651331448 112 +85.93 3023.894178042611 27 +86.05 2289.4422901658822 17 +86.21000000000001 3080.046265886277 21 +86.42 2991.139080684815 148 +87.12 2650.2371591991537 58 +87.14 3061.160890903972 40 +87.2 2986.7247948212434 14 +87.3 2296.176386952884 65 +87.41 2866.022505145415 36 +88.01 2712.7950530771764 36 +88.45 3071.8894836891513 42 +88.49000000000001 3028.9313296936925 21 +88.57 3061.068114237251 33 +88.69 3102.4778806624877 32 +89.78 3057.227829259704 10 +89.80000000000001 3014.607768848213 61 +89.86 2269.5003855474447 32 +89.96000000000001 3097.339826367136 48 +91.13 2865.656120332654 23 +91.17 3106.295060035347 30 +91.25 3075.8616678908043 57 +91.37 3118.5017235845808 22 +92.48 2388.5782381994522 258 +92.56 3017.995692508523 37 +92.66 3129.7420021465027 8 +92.80000000000001 3128.0374038684386 8 +92.97999999999999 3120.59817983668 1 +93.85 2621.0017169013836 65 +93.89 3152.9827148273425 16 +93.97 3112.9114989025948 81 +94.09 9051.577210630201 1 +94.25 3144.593614443685 7 +94.44999999999999 3136.026307287616 39 +95.22 2358.5930127938564 67 +95.24000000000001 2628.2302030073392 75 +95.3 3157.6879199819605 6 +95.4 3069.05881338237 46 +95.72 3148.735619260531 4 +96.61 3138.517643729281 30 +96.65 3154.2341384240963 35 +96.73 3104.341637126945 3 +96.85 2934.527219161547 16 +97.00999999999999 3145.1621579816833 4 +98.0 3169.7397369500227 12 +98.02 3173.4405619138356 51 +98.08000000000001 2803.5762875299115 29 +98.18 3156.589456993101 6 +98.32 2872.565578015583 43 +99.41 3167.053520229805 51 +99.53 2792.167616745098 19 +99.65 3192.3842187305713 50 +99.81 2941.8161057414854 13 +100.82 3106.0143270757785 4 +100.84 3196.712842905975 42 +101.0 2792.6850878679465 45 +101.14 3075.295758134492 67 +101.32 2934.527219161547 73 +102.25 3169.335577057122 11 +102.28999999999999 3064.378077196089 1 +102.37 2867.3070990042206 13 +102.49000000000001 2972.5687544613666 78 +102.65 2899.1883346895556 9 +103.69999999999999 3107.673084479769 14 +103.75999999999999 3107.5662502994205 20 +103.86 3207.86486623112 147 +104.89 3004.323051870421 19 +105.16999999999999 3062.840674929076 13 +105.25 3115.385208926819 37 +105.37 3124.894398215722 47 +105.85 2480.4487497225173 1 +106.58 2407.431203586096 4 +106.6 3050.954276943527 19 +106.66 3204.720580643498 57 +106.9 2971.6609833559414 9 +107.68 2869.1868185951225 90 +108.05 2715.207542711975 40 +108.09 3034.582837887277 35 +108.16 8923.322083170595 1 +108.16999999999999 3132.7657109972333 42 +108.45 3206.7556813701913 41 +108.65 2434.9080064758095 21 +109.52 2983.3921968122127 42 +109.53999999999999 3021.7852339304327 68 +109.6 3228.6035681080452 52 +109.69999999999999 2382.238443145438 26 +110.02 3201.5621187164243 16 +110.65 2278.747462971709 143 +111.00999999999999 3198.4935516583428 24 +111.13 3270.7872141122234 2 +111.25 2250.734324614969 1 +111.41 2266.3973614527526 19 +111.61 3248.176873262908 16 +112.5 3209.6263022351995 52 +112.52 3236.8775077225273 21 +112.58 3265.214388060913 9 +112.68 3261.2028455770733 27 +112.82 2247.8979069343873 12 +113.0 3248.630788501519 44 +114.00999999999999 3246.263698469365 7 +114.05 3283.7113149605584 11 +114.13 3138.9547623372973 9 +114.25 3212.693107036525 19 +114.61 3167.6016163652903 14 +115.53999999999999 3279.512158843141 30 +115.69999999999999 3252.1334535962696 27 +116.02 3175.914986267737 15 +117.09 3308.273416753821 12 +117.16999999999999 3253.6510261550793 13 +117.28999999999999 3282.2183047445214 52 +117.45 3194.5548985735086 48 +118.58 3271.134359820764 28 +118.6 3166.3411060718017 2 +118.66 3274.657997409806 12 +118.75999999999999 3276.1114144668522 71 +118.81 8069.929987304723 2 +118.9 3058.5586474677907 6 +119.08 3124.7374289690324 33 +120.13 3299.07865926231 7 +120.25 3283.969549188908 169 +120.37 3282.865364281636 18 +120.53 3209.4538476195603 85 +121.75999999999999 3202.652026055906 19 +122.0 3247.845439672276 63 +123.28999999999999 2896.068024062971 10 +123.49 3257.744618597351 2 +123.65 3335.6368207585188 17 +124.82 3061.1470072507136 3 +124.84 2652.874101799782 137 +125.32 3291.808317627258 3 +125.44 7472.861366304074 1 +126.41 3291.879098630446 96 +126.45 2954.865309959153 30 +126.81 3347.0017926496544 16 +128.0 2969.6642907911323 30 +128.01999999999998 3156.169355405378 113 +128.5 3339.6354591481986 10 +129.61 3133.040216786245 36 +130.01 3337.7336622325033 8 +131.22 3179.471811480643 3 +131.24 3020.9197275002193 42 +131.72 3079.234482789513 4 +132.25 5694.3046107492355 1 +132.85 3265.6763464862834 6 +132.89 2765.289315785963 54 +133.25 3299.167319188283 1 +133.45 3240.6210824470054 39 +134.5 3285.5763573534555 75 +135.2 3389.542299485286 8 +135.49 2913.1991006451995 84 +136.17000000000002 3337.108329077736 61 +136.97 3390.6201497661164 15 +137.86 2278.6425783786276 15 +138.5 3412.359887233467 24 +139.49 2278.6425783786276 7 +139.57 3314.6464366505215 12 +140.05 3394.3603226528558 10 +141.2 2268.637696945019 37 +141.3 3211.592906954429 16 +141.62 3412.2980526325655 9 +142.93 2764.389625215664 104 +143.20999999999998 3397.420492079248 31 +144.57999999999998 3046.709700644287 25 +144.82 3239.8902759198495 12 +145.0 3390.017846560693 4 +146.20999999999998 3388.321118194083 1 +146.25 3230.394712724747 5 +146.41 6656.233319227925 1 +146.45 3202.770831639379 19 +147.65 3406.1809993011234 1 +147.92 2490.0461843106445 65 +147.94 3282.4850342385416 38 +148.1 3091.0713353140204 13 +148.84 8177.841524509998 1 +149.64999999999998 3420.9264826944177 59 +149.89 2971.110398487407 7 +151.38 3450.2268041391135 48 +151.39999999999998 3435.114699686169 27 +151.56 2916.207468613987 33 +153.13 3376.8393506354428 53 +153.25 2747.6792025271075 6 +154.89999999999998 3029.6093807618167 19 +156.64999999999998 3184.1678661779124 13 +156.69 2963.002024973996 6 +158.44 3278.1976755528335 43 +158.5 2984.3982643072286 41 +160.32999999999998 2929.2353951159334 19 +161.3 3395.699927849927 140 +162.18 2900.2127508167396 26 +164.05 2828.9547539683276 18 +165.94 2834.0869781995048 17 +167.85 2761.479675825987 42 +169.78 2820.7943916563645 30 +182.25 9562.855274446016 1 +182.41 3317.3273881243617 4 +184.34 3322.925969683947 1 +186.29000000000002 3360.9024085801716 3 +188.26 3392.7009888877624 14 +192.08 3491.7183448840774 81 +192.16 3420.003654968807 17 +193.21 9577.942211143269 1 +194.05 3640.672602693079 29 +194.09 3480.2909361143934 84 +198.01 3485.7327780539918 20 +198.25 2896.212181453562 2 +200.0 3494.622726418404 38 +200.18 2942.880901429754 38 +201.64 9784.782930653086 1 +202.01 3437.9077939933177 13 +202.25 2967.623291457324 18 +204.04000000000002 3296.5171014268985 26 +204.2 2866.873035207524 20 +204.34 2955.8289869341224 7 +206.09 3148.6176331844426 31 +206.17000000000002 2744.5052377432257 80 +208.16 3158.060955713173 41 +208.26 2737.0440259520856 26 +210.17000000000002 2736.23335993113 43 +210.25 2968.037904070634 10 +212.26 2868.054567123854 99 +212.36 2936.9548855915373 9 +214.29000000000002 3114.007867684345 21 +214.49 2857.8037021461078 22 +216.4 3288.7281736257864 22 +216.64 2758.698424982332 10 +218.53 3553.019701605945 81 +218.81 2711.7280468365557 27 +220.68 3634.7426318791818 43 +221.0 2744.636952312637 21 +221.22 2778.7531376500506 16 +222.73000000000002 3435.003639008262 25 +223.20999999999998 2813.6142237343056 32 +225.44 2884.218091615126 33 +227.45 2920.3643608289703 13 +229.48000000000002 2901.059806346639 1 +229.7 2872.4863794281077 1 +231.04 4566.623698094688 1 +231.13 3745.4198696541353 4 +231.97000000000003 2805.2536427211 23 +233.3 3798.324367402026 6 +234.26 2917.5335473649657 54 +235.49 3780.4034176262194 43 +236.29000000000002 3127.261581639758 26 +237.7 3790.5283272915926 21 +238.34 3509.404507890192 65 +239.93 3780.8000476089715 23 +240.41 3691.2167370665193 62 +242.18 3810.5668869605215 12 +242.5 3690.6977660057723 7 +242.72 3783.2076337415056 103 +244.45 3796.823145736446 88 +244.61 3815.123720143293 18 +245.04999999999998 3808.475941895918 66 +246.74 3792.3610060225014 23 +248.89 3815.631009413777 26 +249.64 7526.270258235482 1 +250.88 3824.0011767780616 2 +251.06 3777.8631526300683 14 +253.13 3826.4825884877614 43 +253.25 3750.3314520186077 26 +255.38 3834.963624338567 11 +255.45999999999998 3795.2923471058193 13 +257.65 3861.3113057612954 13 +257.69 3831.301214992108 83 +259.88 3807.41697217418 30 +259.94 3846.839351987551 55 +260.0 3830.0822445477593 38 +262.25 3857.996630376963 115 +262.33 3867.2832841673235 26 +262.45 3831.658257204053 60 +264.42 3542.066346075409 27 +264.52 3801.982772186113 32 +264.68 3832.571069138836 36 +264.82 3437.7121752700587 18 +266.81 3789.4339946751943 30 +267.05 3784.653220573848 128 +269.12 3747.1441125208944 93 +269.44 3049.4078113627243 51 +269.62 2788.9302608706444 40 +271.85 2863.6000069842157 18 +272.05 2737.5529218628817 19 +278.48 2678.195287875774 32 +278.89 9754.961199307765 1 diff --git a/reversing_game_mechanics/zoomlevel/win.mass.3 b/reversing_game_mechanics/zoomlevel/win.mass.3 new file mode 100644 index 0000000..ba343eb --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.mass.3 @@ -0,0 +1,126 @@ +60.769999999999996 2830.58244889634 7 +65.46000000000001 3420.4585949840116 1 +66.53 7887.098642720275 1 +66.81 2838.9575551599924 6 +67.7 3143.764145097402 42 +68.26 9958.89833264704 1 +68.33 2134.831609284442 24 +68.59 3184.6464481948383 18 +69.26 1980.0426763077608 8 +69.66 3112.852389690202 14 +70.17 1914.7461972804647 7 +70.75 3137.9294128453557 3 +71.10000000000001 1793.7293552818942 4 +71.18 1948.351354350647 3 +71.86 3120.9783722416278 17 +72.99000000000001 3145.5927899205262 21 +73.14 1833.039006677163 12 +73.9 3145.5927899205262 4 +74.13 1833.8105136572863 8 +74.83 3056.016361212747 21 +75.14 1914.4221060152852 8 +75.78 2881.213980252074 7 +76.16999999999999 1943.2395632036726 13 +76.75 2829.041180329477 6 +76.96000000000001 5461.392679527814 1 +77.14 2411.4835682624916 11 +77.22 2287.895102490497 30 +77.9 2809.5213115404554 26 +78.0 3147.2827963181194 58 +78.17 2468.258090232867 21 +79.24 2355.969651757 20 +79.4 8508.168428046074 1 +80.21 2702.4124407647328 32 +81.2 2982.131452501717 24 +82.25 3122.2384598233366 19 +83.32 3265.692269642074 28 +84.33 3261.3567728784287 5 +84.97 3468.918707609044 1 +85.42 3261.3567728784287 5 +86.45 3274.0054978573266 11 +87.53999999999999 3332.2054258403696 15 +88.65 3361.016661666526 3 +89.78 3355.109089135553 14 +90.83 3373.971102425153 20 +91.98 3259.075482402947 7 +93.05 3265.9854561831717 10 +95.31 3411.079741079062 17 +96.38 2931.623611584543 7 +96.42 3402.4616088943603 17 +96.75999999999999 3406.882592635091 13 +97.61 3376.63575175055 7 +97.85 3455.7640255086862 3 +98.74000000000001 3323.912303295621 14 +98.94 3456.7860795831725 45 +99.65 6587.192725281385 1 +99.89 3373.551392820332 8 +101.06 3336.6609057559326 7 +101.14 7665.473892721832 1 +103.30000000000001 3425.875800434102 11 +104.45 3329.9831831407196 10 +104.75 3409.622413112631 38 +104.89 4313.037096988617 1 +105.30000000000001 3410.078298221318 28 +105.62 3299.869694397038 6 +105.66 3416.254235269969 37 +105.69999999999999 3447.78842158274 23 +106.59 3479.379973501026 105 +106.61000000000001 3463.3119986510023 47 +106.81 3258.0682927157927 5 +106.85000000000001 3271.244564382186 8 +106.97 3457.1297343316464 86 +107.00999999999999 3471.528913893704 33 +107.9 3448.322055725074 8 +107.94 3347.817946065765 4 +108.02000000000001 3247.0983970308016 1 +108.06 3240.0327158842083 8 +108.36000000000001 3461.478441359992 20 +109.29 3211.9752489706393 6 +110.51 2842.601801167374 8 +110.81 3206.3019196575983 20 +111.41 9875.263895208067 1 +111.82000000000001 3040.0726964992136 77 +112.04999999999998 2418.4798944791746 26 +112.5 7247.468592550091 1 +113.04 3227.447288492873 11 +115.4 3130.8784709726438 1 +116.61000000000001 3295.738460497131 2 +117.84 3356.7450007410453 26 +118.6 7029.594867415903 1 +119.09 3271.6653251822686 40 +119.13 3291.6629535844036 39 +120.38 3236.8164915546263 19 +121.63 3177.624899197512 3 +122.9 3060.851025450275 21 +122.99 3527.7692668313784 35 +123.49 7155.990497478319 1 +124.14 3476.978573416868 10 +124.19 2975.672697055239 40 +124.73 2989.411982313579 27 +125.5 3051.0473611532157 4 +125.9 2898.4592458752977 3 +126.41 7350.145372712025 1 +126.83 3049.9652457036295 25 +127.01 2860.5029278083252 25 +128.2 2748.142099673887 18 +129.41 2691.989970263634 1 +130.98 2670.9842755059417 25 +134.3 2809.3913931668544 10 +135.17000000000002 2945.6654596202875 13 +136.98000000000002 2946.8554426710516 4 +137.87 3046.0080433249022 11 +139.7 3122.5574454283465 14 +139.71 3321.6188824126107 59 +140.37 3465.600669436685 28 +140.61 3162.9835598687514 22 +141.32 3303.806289720994 4 +141.54000000000002 3590.769416155819 43 +141.63 3137.2424197055607 2 +142.49 3182.529968437061 1 +143.46 3185.424932406978 15 +168.81 2838.9635432671553 12 +202.01 9721.27075026717 1 +216.49 3464.951947718756 23 +216.91000000000003 3738.3038934789665 3 +218.3 3524.6476419636615 4 +264.42 9773.704773523703 1 diff --git a/reversing_game_mechanics/zoomlevel/win.mass.4 b/reversing_game_mechanics/zoomlevel/win.mass.4 new file mode 100644 index 0000000..aa0de62 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.mass.4 @@ -0,0 +1,130 @@ +75.78 3431.546152975361 6 +76.63 3497.8764986774477 14 +76.96000000000001 5461.392679527814 1 +77.5 3311.0096647397454 23 +78.35 3389.6768282536905 36 +79.24 3468.8963662813567 13 +79.4 8508.168428046074 1 +80.13 3486.8789769649306 21 +80.14999999999999 3507.4472198452254 16 +81.03999999999999 3426.4974828533 11 +81.08 3490.3886603070437 102 +81.93 3354.6057890607653 35 +82.03 3519.1081256477473 63 +82.86 3395.7847399386196 11 +83.0 3404.603501143709 4 +83.87 3419.91418020979 18 +84.78 3187.2913265028033 64 +85.71000000000001 3413.126719007075 8 +85.77 3115.806476660577 49 +96.38999999999999 3615.2654121101536 87 +97.25999999999999 3652.2186407716613 3 +97.47999999999999 3627.734279133465 58 +98.26 3649.020964587625 1 +98.36999999999999 3593.768078215399 9 +98.58999999999999 3627.231726813163 147 +98.94 5135.193180397404 1 +99.21000000000001 3664.0061408245483 74 +99.24 3584.0772871131003 3 +99.65 6587.192725281385 1 +100.13 3584.0772871131003 2 +100.18 3573.493808585654 1 +100.38 2493.193935497197 1 +101.02 3677.116261420082 10 +101.14 7665.473892721832 1 +101.17 3670.228875696991 45 +101.32999999999998 2823.253796597111 33 +101.42999999999999 2493.193935497197 53 +102.12 3707.9920442201596 9 +102.15 3654.805603585504 14 +102.26 2755.466203748469 1 +103.06 3683.1563909234155 43 +103.09 3675.8706451669377 16 +103.33 2441.627530971913 36 +103.99000000000001 3684.5929218843157 4 +105.09 3716.556605246313 8 +106.10000000000001 3684.0620244507286 15 +107.13 3732.4611183507322 7 +107.15 3715.699799499416 23 +109.23 3690.992549437075 16 +110.3 3509.5711988788603 21 +110.5 2476.2915821849415 5 +110.98 3468.918707609044 5 +111.32999999999998 3555.6774319389547 25 +111.41 9875.263895208067 1 +111.51 2465.023326461638 1 +112.41999999999999 3459.260036481791 17 +112.53999999999999 2540.530850039023 35 +113.52999999999999 3586.7179983935175 15 +114.66 3585.6561463698663 10 +115.80999999999999 3670.9509667114867 23 +115.85000000000001 3782.2038548973005 17 +116.86 3734.5910083970375 112 +116.88000000000001 3796.5963704349715 139 +116.97999999999999 3743.2312244904133 16 +117.92999999999999 3784.865915722775 12 +117.97 3800.631526470305 29 +118.03 3744.2478550437872 29 +118.6 7029.594867415903 1 +118.82 3733.0740683784993 1 +119.02 3689.460258628625 9 +119.91 3723.439404636525 3 +120.13 3625.2627490983327 4 +121.2 3526.8682992139074 20 +122.13 3630.5692391138887 8 +122.33 3313.4086678223075 20 +123.26 3661.392221546334 13 +123.46000000000001 3634.4388837893534 11 +123.49 7155.990497478319 1 +124.41 3814.323662197533 12 +124.57000000000001 3220.6027386189685 5 +124.63000000000001 3634.4388837893534 40 +125.53999999999999 3831.4364147144606 11 +125.60000000000001 3827.5533961004385 69 +126.41 7350.145372712025 1 +126.63000000000001 3590.791834679365 5 +126.71000000000001 3812.6926180850196 47 +126.77 3832.2616038052515 5 +126.77000000000001 3832.5211023554716 6 +126.83 9346.260482139367 1 +127.70000000000002 3814.195852338996 13 +127.72 3636.3681056790715 28 +127.80000000000001 3813.7278350716115 66 +127.86 3826.231827790888 3 +127.96000000000001 3856.772873789692 16 +128.85000000000002 3768.2490628938 180 +128.95 3838.2737005065183 19 +129.13 3854.4753209743085 28 +130.34 3835.5570651471216 1 +130.98 7269.414075425887 1 +131.57 3876.429542762257 43 +132.76 3793.3906996248093 27 +135.07 2951.3117422597024 5 +202.01 9721.27075026717 1 +204.5 3049.217932519747 3 +205.93 2999.563301549077 1 +207.38 2918.4139528175233 2 +208.85 2928.8649678672455 1 +210.34 2923.3942601024582 1 +211.79 2926.6731966517887 1 +213.29999999999998 2921.918034442445 3 +213.39999999999998 3027.5617252171755 7 +213.42 3092.014553652683 2 +214.82999999999998 3092.7083599977545 25 +214.86999999999998 3098.9601481787404 28 +216.29999999999998 3112.9012191201955 7 +216.35999999999999 2853.4514188960707 21 +217.86999999999998 2832.8236796525125 40 +219.29999999999998 2666.3600657075553 5 +220.82999999999998 2658.3432810681165 14 +222.27999999999997 2840.7354681490497 2 +223.74999999999997 2840.7354681490497 9 +225.17999999999998 2840.7354681490497 2 +226.63 2840.7354681490497 4 +228.1 2840.7354681490497 63 +264.42 9773.704773523703 1 +264.52 3771.882951524344 154 +265.45 3702.6188029555515 4 +266.39 3661.2525179233403 51 +267.3 3601.816902620121 2 +269.17 3550.685708423093 49 diff --git a/reversing_game_mechanics/zoomlevel/win.mass.5 b/reversing_game_mechanics/zoomlevel/win.mass.5 new file mode 100644 index 0000000..f4b686e --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.mass.5 @@ -0,0 +1,8 @@ +126.83 9346.260482139367 1 +129.32999999999998 3926.380139517823 7 +130.22 3995.193362028927 19 +130.98 7269.414075425887 1 +131.06 2999.2432378851836 13 +131.23000000000002 3979.0382003695313 11 +133.33999999999997 3046.871510254412 16 +134.51 3030.115674359644 1 diff --git a/reversing_game_mechanics/zoomlevel/win.mass.6 b/reversing_game_mechanics/zoomlevel/win.mass.6 new file mode 100644 index 0000000..7994d85 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.mass.6 @@ -0,0 +1,4 @@ +126.83 9346.260482139367 1 +127.14 3564.1046561513876 2 +128.13 3713.46266980025 16 +129.01999999999998 3981.4374288691265 52 diff --git a/reversing_game_mechanics/zoomlevel/win.mass.gnuplot b/reversing_game_mechanics/zoomlevel/win.mass.gnuplot new file mode 100644 index 0000000..a948115 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.mass.gnuplot @@ -0,0 +1,9 @@ +min(a,b)=(ab)?a:b +plot "win.mass.1" using 1:2:(min(1,$3/100)) lt rgb "red" pt 2 ps variable, \ + "win.mass.2" using 1:2:(min(1,$3/100)) lt rgb "blue" pt 2 ps variable, \ + "win.mass.3" using 1:2:(min(1,$3/100)) lt rgb "green" pt 2 ps variable, \ + "win.mass.4" using 1:2:(1) lt rgb "purple" pt 2 ps variable, \ + "win.mass.5" using 1:2:(1) lt rgb "cyan" pt 2 ps variable, \ + "win.mass.6" using 1:2:(1) lt rgb "orange" pt 2 ps variable +pause -1 diff --git a/reversing_game_mechanics/zoomlevel/win.size.1 b/reversing_game_mechanics/zoomlevel/win.size.1 new file mode 100644 index 0000000..8357f6a --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.1 @@ -0,0 +1,116 @@ +0 9957.478596512272 16 +49 2120.5192760265113 245 +50 1969.829688069504 88 +51 1907.5106814904077 196 +52 1652.2645066695586 49 +53 1860.7818249327352 96 +54 1851.8933554608375 58 +55 1468.638825579659 70 +56 2251.943604977709 106 +57 2004.575765592311 166 +58 2109.127781809343 362 +59 2126.4564420650613 137 +60 1994.1740144731602 91 +61 2173.5730951592127 58 +62 1940.5630626186824 52 +63 2232.8013794334684 39 +64 2133.3471353720192 71 +65 2239.5713875650404 100 +66 2259.5827048373335 868 +67 2240.224319125208 818 +68 2307.553032976707 443 +69 2226.5634956138124 579 +70 2356.425258734085 336 +71 2293.2538019155227 397 +72 2249.2098612623945 273 +73 2331.4519081465096 451 +74 2392.639755583778 300 +75 2404.2996901384818 277 +76 2403.8011565019265 161 +77 2357.5313359529287 262 +78 2377.4242364374095 157 +79 2339.8472172344927 145 +80 2438.0258407162137 228 +81 2488.3331770484433 301 +82 2489.7003835803216 352 +83 2499.0544211761376 291 +84 2455.6426857342253 304 +85 2498.9455776386967 154 +86 2378.6727391551785 346 +87 2474.5797623030867 702 +88 2366.7634017788937 727 +89 2442.546417163858 373 +90 2515.553616999646 238 +91 2614.3163542310635 207 +92 2594.101771326638 66 +93 2544.643000501249 67 +94 2651.225377066235 95 +95 2681.96290056369 148 +96 2685.0344504307577 170 +97 2679.5546271722096 426 +98 2693.4938277263605 569 +99 2726.821592990638 54 +100 2696.036349903317 53 +101 2704.8558187082726 56 +102 2754.743726737571 88 +103 2719.114010114324 180 +104 2791.1581825471662 122 +105 2794.8023185907086 84 +106 2803.209767391659 133 +107 2805.824121358999 90 +108 2796.2517769328283 250 +109 2803.5384784232942 261 +110 2837.5144052497776 142 +111 2835.092414719492 107 +112 2846.737255174773 63 +113 2877.452345391666 63 +114 2851.5078467365297 53 +115 2780.2778638114573 113 +116 2891.1260781916794 242 +117 2870.733878296628 69 +118 2892.3390188565377 88 +119 2730.286798122131 145 +120 2715.363695713707 389 +121 2238.8311682661556 281 +122 2913.41998345587 61 +123 2955.795155283938 28 +124 2385.1079640133694 322 +125 3029.202205201891 67 +126 3015.162516349658 39 +127 3024.4353191959653 64 +128 3046.6238691377707 139 +129 3020.514029101669 40 +130 3015.3225366451265 112 +131 3021.6586504765887 92 +132 3040.8763539479864 73 +133 3065.0941257977706 58 +134 2976.10500486794 66 +135 3026.624522467232 98 +136 3013.2540550043236 84 +137 2927.263910206936 80 +138 2981.869380103696 80 +139 2977.177354475208 52 +140 3049.6730972351775 42 +141 2354.0403564934904 65 +142 2332.625130620006 4 +148 3144.616033794905 7 +149 3228.400223020684 11 +150 3220.1863300125974 71 +151 3248.3468103021264 119 +152 3253.712494981694 66 +153 3238.846245192877 57 +154 3176.819950831334 43 +155 3301.4617974467005 36 +156 3296.8477368541 132 +157 3316.3596005258537 113 +158 3286.2537942161434 155 +159 3083.007946794818 110 +160 2909.176000175995 64 +161 2641.6837433727756 35 +162 2646.5972492995606 65 +163 2727.742106578259 49 +164 2692.4384858339845 44 +165 2498.7140692764347 49 +166 2352.3938870860893 36 +167 2375.1743093928917 57 +168 2304.796954180563 121 diff --git a/reversing_game_mechanics/zoomlevel/win.size.2 b/reversing_game_mechanics/zoomlevel/win.size.2 new file mode 100644 index 0000000..6168704 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.2 @@ -0,0 +1,150 @@ +64 7513.947364734464 1 +66 8967.320224013414 2 +68 9047.885167264227 3 +71 5962.59423405618 1 +73 6812.90341924792 1 +74 9453.725720582335 1 +75 9562.746467411964 1 +78 4983.02087091756 1 +80 7724.4858728591125 1 +83 8841.674502038626 2 +84 6246.4982190023875 1 +87 9393.411414390408 1 +89 9939.87610586772 1 +90 2459.633306003153 36 +91 2476.9733547214432 54 +92 2602.3854441646417 92 +93 2641.4407053727327 16 +94 2490.116463139827 22 +95 2708.966592632696 50 +96 2712.70344859146 186 +97 2601.976556389392 122 +98 2696.738771182704 66 +99 2717.4488035655795 96 +100 2664.1535241047955 169 +101 2756.752618571351 135 +102 2690.486944774124 169 +103 2757.303936819443 122 +104 2788.0634856473407 455 +105 2799.2456126606685 442 +106 2824.3450568229086 140 +107 2810.7694676013543 170 +108 2763.8178304656767 344 +109 2737.670725269933 72 +110 2784.720632307665 251 +111 2785.9047004519016 159 +112 2875.0377388827437 260 +113 2811.6308434785674 181 +114 2870.785606763417 187 +115 2835.5659047181393 273 +116 2866.9461104108673 57 +117 2881.5004771819836 117 +118 2909.6427615774414 109 +119 2619.34037497993 258 +120 2939.450458844306 263 +121 2906.4929038275664 204 +122 2948.7314221542797 121 +123 2953.9094434325502 74 +124 2985.440838469254 88 +125 2975.29695996887 115 +126 2954.414493601059 126 +127 2896.9544352647317 185 +128 2949.3024599047144 314 +129 2910.3683615652503 209 +130 2979.817444072707 119 +131 3028.992076582572 177 +132 2808.3669632012125 177 +133 3073.615623333536 128 +134 3060.4393475447278 151 +135 3086.498663534459 133 +136 2561.4052783579564 312 +137 3126.1601046651467 227 +138 2979.8711381534604 198 +139 3155.1700429612347 90 +140 3151.571195451564 231 +141 3164.168927222439 154 +142 3129.1259162903625 232 +143 2847.00140498736 255 +144 3187.418077378617 219 +145 3138.7672739468912 97 +146 3195.2003067100504 89 +147 3194.6325297285757 158 +148 3195.955099809758 204 +149 3237.0166820700815 62 +150 3255.597180242052 127 +151 3254.93502239292 60 +152 3281.352160314403 73 +153 3279.3377380196753 125 +154 3255.6776560341473 152 +155 3271.2471627805808 279 +156 3247.845439672276 82 +157 3326.7739628655268 29 +158 2729.1090121136604 144 +159 3286.8233904485955 142 +160 3261.8871838247255 153 +161 3328.385344277312 44 +162 3046.827366294323 49 +163 3154.2986542177646 184 +164 3295.002427920198 83 +165 3357.799874918099 76 +166 3378.6307877600357 39 +167 3370.5692397575813 30 +168 3195.0414707793702 62 +169 2902.5402667318845 135 +170 3258.0098219618676 41 +171 3262.259952854769 26 +172 3422.502739224616 116 +173 3417.901402907931 66 +174 3439.523368142743 108 +175 3349.7058079777694 59 +176 3029.6093807618167 19 +177 3441.201679646225 19 +178 3409.1941863144143 224 +179 2929.2353951159334 19 +180 2900.2127508167396 26 +181 2828.9547539683276 18 +182 2834.0869781995048 17 +183 2761.479675825987 42 +184 2820.7943916563645 30 +191 3317.3273881243617 4 +192 3322.925969683947 1 +193 3360.9024085801716 3 +194 3392.7009888877624 14 +196 3491.7183448840774 98 +197 3560.370767209505 113 +199 3481.1977823731877 22 +200 3588.148547649609 76 +201 3452.222617387239 31 +202 3451.376536977674 53 +203 3230.5573822484566 111 +204 3113.641758455844 67 +205 2726.8489140397933 53 +206 2873.5044805950797 108 +207 3104.405418111494 43 +208 3249.613515481495 32 +209 3475.2795571004067 108 +210 3639.9057680110345 80 +211 3325.2151810070877 57 +212 2884.218091615126 33 +213 2920.3643608289703 13 +214 2906.8321244956683 2 +215 2813.3490718359144 27 +216 2939.36336644519 60 +217 3755.401043830073 69 +218 3585.3395933997663 86 +219 3758.964219036941 85 +220 3790.129945001886 122 +221 3810.992521640524 172 +222 3792.3610060225014 23 +223 3815.631009413777 26 +224 3795.2923471058193 16 +225 3826.4825884877614 69 +226 3831.510668130783 54 +227 3832.1638795855274 156 +228 3833.123269606653 120 +229 3859.508388383163 141 +230 3830.84912258366 86 +231 3783.793995449541 158 +232 3746.1261324199963 184 +233 2863.6000069842157 37 +236 2678.195287875774 32 diff --git a/reversing_game_mechanics/zoomlevel/win.size.3 b/reversing_game_mechanics/zoomlevel/win.size.3 new file mode 100644 index 0000000..564d37c --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.3 @@ -0,0 +1,69 @@ +115 7887.098642720275 1 +116 9958.89833264704 1 +124 5461.392679527814 1 +126 8508.168428046074 1 +135 2830.58244889634 7 +137 4313.037096988617 1 +140 3420.4585949840116 1 +141 3163.25923692637 7 +142 3149.401212929213 43 +143 3176.547339486695 42 +144 3058.668010752393 23 +145 3126.600230282087 10 +146 3120.9783722416278 24 +147 3145.5927899205262 21 +148 3099.849351178215 16 +149 3050.773016794268 30 +150 2843.040801676965 15 +151 2624.4180307260503 19 +152 3056.6098867863398 125 +153 2468.258090232867 21 +154 2355.969651757 21 +155 2702.4124407647328 32 +156 2982.131452501717 24 +157 3142.504256162591 21 +158 3265.692269642074 28 +159 3282.8310952590905 6 +160 3261.3567728784287 5 +161 3274.0054978573266 11 +162 3332.2054258403696 15 +163 3361.016661666526 3 +164 3355.109089135553 14 +165 3373.971102425153 20 +166 3259.075482402947 7 +167 3265.9854561831717 10 +169 3411.079741079062 17 +170 3398.256611852613 37 +171 3409.9420816195693 33 +172 3456.7860795831725 82 +173 3373.551392820332 8 +174 3336.6609057559326 7 +175 3430.284244782056 15 +176 3437.843510109208 76 +177 3458.1489268104115 281 +178 3477.0933263287598 38 +179 3252.7631330916183 13 +180 3240.0327158842083 9 +181 3159.548227199579 60 +182 3040.0726964992136 77 +184 3227.447288492873 11 +186 3130.8784709726438 1 +187 3295.738460497131 2 +188 3356.7450007410453 26 +189 3489.3794577259723 114 +190 3467.191514756576 29 +191 3003.702382061179 30 +192 3060.0434637436115 34 +193 2897.203134058777 78 +194 2949.2990692705275 26 +195 3061.7589715717336 37 +196 3085.414720908682 39 +197 3373.3670123483453 109 +198 3590.769416155819 47 +199 3188.3251088933825 3 +200 3185.424932406978 15 +201 9721.27075026717 1 +225 2838.9635432671553 12 +228 9773.704773523703 1 +253 3503.388645297578 26 +254 3524.6476419636615 4 diff --git a/reversing_game_mechanics/zoomlevel/win.size.4 b/reversing_game_mechanics/zoomlevel/win.size.4 new file mode 100644 index 0000000..69a1ad2 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.4 @@ -0,0 +1,77 @@ +124 5461.392679527814 1 +126 8508.168428046074 1 +141 6587.192725281385 1 +142 7665.473892721832 1 +149 9875.263895208067 1 +154 7029.594867415903 1 +157 7155.990497478319 1 +159 7350.145372712025 1 +172 5135.193180397404 1 +174 3431.546152975361 6 +175 3497.8764986774477 14 +176 3311.0096647397454 23 +177 3389.6768282536905 36 +178 3468.8963662813567 13 +179 3485.865889560297 37 +180 3490.3886603070437 113 +181 3515.5905620535505 98 +182 3499.1920496023076 15 +183 3419.91418020979 18 +184 3187.2913265028033 64 +185 3123.9286163419292 57 +195 3615.2654121101536 88 +196 3637.733635108541 62 +197 3628.236210612534 156 +198 3661.8806643581383 4 +199 3664.0061408245483 76 +200 3677.116261420082 12 +201 3637.3748775731106 146 +202 3685.892700554372 53 +203 3635.77777098656 56 +205 3716.556605246313 8 +206 3684.0620244507286 15 +207 3715.699799499416 30 +208 3468.918707609044 5 +209 3690.992549437075 16 +210 3509.5711988788603 26 +211 3555.6774319389547 26 +212 3433.242199437727 52 +213 3586.7179983935175 15 +214 3585.6561463698663 10 +215 3746.0168179013826 40 +216 3784.0027748404204 267 +217 3786.887112127849 70 +218 3689.460258628625 10 +219 3681.7335590724106 7 +220 3526.8682992139074 20 +221 3674.9727890149065 28 +222 3664.5142925086266 24 +223 3634.4388837893534 57 +224 3824.525199289449 80 +225 3828.2075440080307 63 +226 3813.7278350716115 126 +227 3816.3041021386125 227 +228 9773.704773523703 2 +229 3870.390807140798 48 +230 3793.3906996248093 27 +286 3049.217932519747 3 +287 2999.563301549077 1 +288 2918.4139528175233 2 +289 2928.8649678672455 1 +290 2923.3942601024582 1 +291 2926.6731966517887 1 +292 3092.7083599977545 12 +293 3092.7083599977545 53 +294 3101.7430583463874 28 +295 2832.8236796525125 40 +296 2666.3600657075553 5 +297 2658.3432810681165 14 +298 2840.7354681490497 2 +299 2840.7354681490497 9 +300 2840.7354681490497 2 +301 2840.7354681490497 4 +302 2840.7354681490497 63 +322 3771.882951524344 154 +323 3668.3926998073694 55 +324 3601.816902620121 2 +325 3550.685708423093 49 diff --git a/reversing_game_mechanics/zoomlevel/win.size.5 b/reversing_game_mechanics/zoomlevel/win.size.5 new file mode 100644 index 0000000..537d012 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.5 @@ -0,0 +1,8 @@ +195 9346.260482139367 1 +196 7269.414075425887 1 +251 3926.380139517823 7 +252 3995.193362028927 19 +253 3979.0382003695313 11 +254 2999.2432378851836 13 +256 3046.871510254412 16 +257 3030.115674359644 1 diff --git a/reversing_game_mechanics/zoomlevel/win.size.6 b/reversing_game_mechanics/zoomlevel/win.size.6 new file mode 100644 index 0000000..1e93f8a --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.6 @@ -0,0 +1,4 @@ +195 9346.260482139367 1 +276 3564.1046561513876 2 +277 3713.46266980025 16 +278 3981.4374288691265 52 diff --git a/reversing_game_mechanics/zoomlevel/win.size.all b/reversing_game_mechanics/zoomlevel/win.size.all new file mode 100644 index 0000000..e4520ab --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.all @@ -0,0 +1,424 @@ +0 9957.478596512272 16 +49 2120.5192760265113 245 +50 1969.829688069504 88 +51 1907.5106814904077 196 +52 1652.2645066695586 49 +53 1860.7818249327352 96 +54 1851.8933554608375 58 +55 1468.638825579659 70 +56 2251.943604977709 106 +57 2004.575765592311 166 +58 2109.127781809343 362 +59 2126.4564420650613 137 +60 1994.1740144731602 91 +61 2173.5730951592127 58 +62 1940.5630626186824 52 +63 2232.8013794334684 39 +64 2133.3471353720192 71 +65 2239.5713875650404 100 +66 2259.5827048373335 868 +67 2240.224319125208 818 +68 2307.553032976707 443 +69 2226.5634956138124 579 +70 2356.425258734085 336 +71 2293.2538019155227 397 +72 2249.2098612623945 273 +73 2331.4519081465096 451 +74 2392.639755583778 300 +75 2404.2996901384818 277 +76 2403.8011565019265 161 +77 2357.5313359529287 262 +78 2377.4242364374095 157 +79 2339.8472172344927 145 +80 2438.0258407162137 228 +81 2488.3331770484433 301 +82 2489.7003835803216 352 +83 2499.0544211761376 291 +84 2455.6426857342253 304 +85 2498.9455776386967 154 +86 2378.6727391551785 346 +87 2474.5797623030867 702 +88 2366.7634017788937 727 +89 2442.546417163858 373 +90 2515.553616999646 238 +91 2614.3163542310635 207 +92 2594.101771326638 66 +93 2544.643000501249 67 +94 2651.225377066235 95 +95 2681.96290056369 148 +96 2685.0344504307577 170 +97 2679.5546271722096 426 +98 2693.4938277263605 569 +99 2726.821592990638 54 +100 2696.036349903317 53 +101 2704.8558187082726 56 +102 2754.743726737571 88 +103 2719.114010114324 180 +104 2791.1581825471662 122 +105 2794.8023185907086 84 +106 2803.209767391659 133 +107 2805.824121358999 90 +108 2796.2517769328283 250 +109 2803.5384784232942 261 +110 2837.5144052497776 142 +111 2835.092414719492 107 +112 2846.737255174773 63 +113 2877.452345391666 63 +114 2851.5078467365297 53 +115 2780.2778638114573 113 +116 2891.1260781916794 242 +117 2870.733878296628 69 +118 2892.3390188565377 88 +119 2730.286798122131 145 +120 2715.363695713707 389 +121 2238.8311682661556 281 +122 2913.41998345587 61 +123 2955.795155283938 28 +124 2385.1079640133694 322 +125 3029.202205201891 67 +126 3015.162516349658 39 +127 3024.4353191959653 64 +128 3046.6238691377707 139 +129 3020.514029101669 40 +130 3015.3225366451265 112 +131 3021.6586504765887 92 +132 3040.8763539479864 73 +133 3065.0941257977706 58 +134 2976.10500486794 66 +135 3026.624522467232 98 +136 3013.2540550043236 84 +137 2927.263910206936 80 +138 2981.869380103696 80 +139 2977.177354475208 52 +140 3049.6730972351775 42 +141 2354.0403564934904 65 +142 2332.625130620006 4 +148 3144.616033794905 7 +149 3228.400223020684 11 +150 3220.1863300125974 71 +151 3248.3468103021264 119 +152 3253.712494981694 66 +153 3238.846245192877 57 +154 3176.819950831334 43 +155 3301.4617974467005 36 +156 3296.8477368541 132 +157 3316.3596005258537 113 +158 3286.2537942161434 155 +159 3083.007946794818 110 +160 2909.176000175995 64 +161 2641.6837433727756 35 +162 2646.5972492995606 65 +163 2727.742106578259 49 +164 2692.4384858339845 44 +165 2498.7140692764347 49 +166 2352.3938870860893 36 +167 2375.1743093928917 57 +168 2304.796954180563 121 +64 7513.947364734464 1 +66 8967.320224013414 2 +68 9047.885167264227 3 +71 5962.59423405618 1 +73 6812.90341924792 1 +74 9453.725720582335 1 +75 9562.746467411964 1 +78 4983.02087091756 1 +80 7724.4858728591125 1 +83 8841.674502038626 2 +84 6246.4982190023875 1 +87 9393.411414390408 1 +89 9939.87610586772 1 +90 2459.633306003153 36 +91 2476.9733547214432 54 +92 2602.3854441646417 92 +93 2641.4407053727327 16 +94 2490.116463139827 22 +95 2708.966592632696 50 +96 2712.70344859146 186 +97 2601.976556389392 122 +98 2696.738771182704 66 +99 2717.4488035655795 96 +100 2664.1535241047955 169 +101 2756.752618571351 135 +102 2690.486944774124 169 +103 2757.303936819443 122 +104 2788.0634856473407 455 +105 2799.2456126606685 442 +106 2824.3450568229086 140 +107 2810.7694676013543 170 +108 2763.8178304656767 344 +109 2737.670725269933 72 +110 2784.720632307665 251 +111 2785.9047004519016 159 +112 2875.0377388827437 260 +113 2811.6308434785674 181 +114 2870.785606763417 187 +115 2835.5659047181393 273 +116 2866.9461104108673 57 +117 2881.5004771819836 117 +118 2909.6427615774414 109 +119 2619.34037497993 258 +120 2939.450458844306 263 +121 2906.4929038275664 204 +122 2948.7314221542797 121 +123 2953.9094434325502 74 +124 2985.440838469254 88 +125 2975.29695996887 115 +126 2954.414493601059 126 +127 2896.9544352647317 185 +128 2949.3024599047144 314 +129 2910.3683615652503 209 +130 2979.817444072707 119 +131 3028.992076582572 177 +132 2808.3669632012125 177 +133 3073.615623333536 128 +134 3060.4393475447278 151 +135 3086.498663534459 133 +136 2561.4052783579564 312 +137 3126.1601046651467 227 +138 2979.8711381534604 198 +139 3155.1700429612347 90 +140 3151.571195451564 231 +141 3164.168927222439 154 +142 3129.1259162903625 232 +143 2847.00140498736 255 +144 3187.418077378617 219 +145 3138.7672739468912 97 +146 3195.2003067100504 89 +147 3194.6325297285757 158 +148 3195.955099809758 204 +149 3237.0166820700815 62 +150 3255.597180242052 127 +151 3254.93502239292 60 +152 3281.352160314403 73 +153 3279.3377380196753 125 +154 3255.6776560341473 152 +155 3271.2471627805808 279 +156 3247.845439672276 82 +157 3326.7739628655268 29 +158 2729.1090121136604 144 +159 3286.8233904485955 142 +160 3261.8871838247255 153 +161 3328.385344277312 44 +162 3046.827366294323 49 +163 3154.2986542177646 184 +164 3295.002427920198 83 +165 3357.799874918099 76 +166 3378.6307877600357 39 +167 3370.5692397575813 30 +168 3195.0414707793702 62 +169 2902.5402667318845 135 +170 3258.0098219618676 41 +171 3262.259952854769 26 +172 3422.502739224616 116 +173 3417.901402907931 66 +174 3439.523368142743 108 +175 3349.7058079777694 59 +176 3029.6093807618167 19 +177 3441.201679646225 19 +178 3409.1941863144143 224 +179 2929.2353951159334 19 +180 2900.2127508167396 26 +181 2828.9547539683276 18 +182 2834.0869781995048 17 +183 2761.479675825987 42 +184 2820.7943916563645 30 +191 3317.3273881243617 4 +192 3322.925969683947 1 +193 3360.9024085801716 3 +194 3392.7009888877624 14 +196 3491.7183448840774 98 +197 3560.370767209505 113 +199 3481.1977823731877 22 +200 3588.148547649609 76 +201 3452.222617387239 31 +202 3451.376536977674 53 +203 3230.5573822484566 111 +204 3113.641758455844 67 +205 2726.8489140397933 53 +206 2873.5044805950797 108 +207 3104.405418111494 43 +208 3249.613515481495 32 +209 3475.2795571004067 108 +210 3639.9057680110345 80 +211 3325.2151810070877 57 +212 2884.218091615126 33 +213 2920.3643608289703 13 +214 2906.8321244956683 2 +215 2813.3490718359144 27 +216 2939.36336644519 60 +217 3755.401043830073 69 +218 3585.3395933997663 86 +219 3758.964219036941 85 +220 3790.129945001886 122 +221 3810.992521640524 172 +222 3792.3610060225014 23 +223 3815.631009413777 26 +224 3795.2923471058193 16 +225 3826.4825884877614 69 +226 3831.510668130783 54 +227 3832.1638795855274 156 +228 3833.123269606653 120 +229 3859.508388383163 141 +230 3830.84912258366 86 +231 3783.793995449541 158 +232 3746.1261324199963 184 +233 2863.6000069842157 37 +236 2678.195287875774 32 +115 7887.098642720275 1 +116 9958.89833264704 1 +124 5461.392679527814 1 +126 8508.168428046074 1 +135 2830.58244889634 7 +137 4313.037096988617 1 +140 3420.4585949840116 1 +141 3163.25923692637 7 +142 3149.401212929213 43 +143 3176.547339486695 42 +144 3058.668010752393 23 +145 3126.600230282087 10 +146 3120.9783722416278 24 +147 3145.5927899205262 21 +148 3099.849351178215 16 +149 3050.773016794268 30 +150 2843.040801676965 15 +151 2624.4180307260503 19 +152 3056.6098867863398 125 +153 2468.258090232867 21 +154 2355.969651757 21 +155 2702.4124407647328 32 +156 2982.131452501717 24 +157 3142.504256162591 21 +158 3265.692269642074 28 +159 3282.8310952590905 6 +160 3261.3567728784287 5 +161 3274.0054978573266 11 +162 3332.2054258403696 15 +163 3361.016661666526 3 +164 3355.109089135553 14 +165 3373.971102425153 20 +166 3259.075482402947 7 +167 3265.9854561831717 10 +169 3411.079741079062 17 +170 3398.256611852613 37 +171 3409.9420816195693 33 +172 3456.7860795831725 82 +173 3373.551392820332 8 +174 3336.6609057559326 7 +175 3430.284244782056 15 +176 3437.843510109208 76 +177 3458.1489268104115 281 +178 3477.0933263287598 38 +179 3252.7631330916183 13 +180 3240.0327158842083 9 +181 3159.548227199579 60 +182 3040.0726964992136 77 +184 3227.447288492873 11 +186 3130.8784709726438 1 +187 3295.738460497131 2 +188 3356.7450007410453 26 +189 3489.3794577259723 114 +190 3467.191514756576 29 +191 3003.702382061179 30 +192 3060.0434637436115 34 +193 2897.203134058777 78 +194 2949.2990692705275 26 +195 3061.7589715717336 37 +196 3085.414720908682 39 +197 3373.3670123483453 109 +198 3590.769416155819 47 +199 3188.3251088933825 3 +200 3185.424932406978 15 +201 9721.27075026717 1 +225 2838.9635432671553 12 +228 9773.704773523703 1 +253 3503.388645297578 26 +254 3524.6476419636615 4 +124 5461.392679527814 1 +126 8508.168428046074 1 +141 6587.192725281385 1 +142 7665.473892721832 1 +149 9875.263895208067 1 +154 7029.594867415903 1 +157 7155.990497478319 1 +159 7350.145372712025 1 +172 5135.193180397404 1 +174 3431.546152975361 6 +175 3497.8764986774477 14 +176 3311.0096647397454 23 +177 3389.6768282536905 36 +178 3468.8963662813567 13 +179 3485.865889560297 37 +180 3490.3886603070437 113 +181 3515.5905620535505 98 +182 3499.1920496023076 15 +183 3419.91418020979 18 +184 3187.2913265028033 64 +185 3123.9286163419292 57 +195 3615.2654121101536 88 +196 3637.733635108541 62 +197 3628.236210612534 156 +198 3661.8806643581383 4 +199 3664.0061408245483 76 +200 3677.116261420082 12 +201 3637.3748775731106 146 +202 3685.892700554372 53 +203 3635.77777098656 56 +205 3716.556605246313 8 +206 3684.0620244507286 15 +207 3715.699799499416 30 +208 3468.918707609044 5 +209 3690.992549437075 16 +210 3509.5711988788603 26 +211 3555.6774319389547 26 +212 3433.242199437727 52 +213 3586.7179983935175 15 +214 3585.6561463698663 10 +215 3746.0168179013826 40 +216 3784.0027748404204 267 +217 3786.887112127849 70 +218 3689.460258628625 10 +219 3681.7335590724106 7 +220 3526.8682992139074 20 +221 3674.9727890149065 28 +222 3664.5142925086266 24 +223 3634.4388837893534 57 +224 3824.525199289449 80 +225 3828.2075440080307 63 +226 3813.7278350716115 126 +227 3816.3041021386125 227 +228 9773.704773523703 2 +229 3870.390807140798 48 +230 3793.3906996248093 27 +286 3049.217932519747 3 +287 2999.563301549077 1 +288 2918.4139528175233 2 +289 2928.8649678672455 1 +290 2923.3942601024582 1 +291 2926.6731966517887 1 +292 3092.7083599977545 12 +293 3092.7083599977545 53 +294 3101.7430583463874 28 +295 2832.8236796525125 40 +296 2666.3600657075553 5 +297 2658.3432810681165 14 +298 2840.7354681490497 2 +299 2840.7354681490497 9 +300 2840.7354681490497 2 +301 2840.7354681490497 4 +302 2840.7354681490497 63 +322 3771.882951524344 154 +323 3668.3926998073694 55 +324 3601.816902620121 2 +325 3550.685708423093 49 +195 9346.260482139367 1 +196 7269.414075425887 1 +251 3926.380139517823 7 +252 3995.193362028927 19 +253 3979.0382003695313 11 +254 2999.2432378851836 13 +256 3046.871510254412 16 +257 3030.115674359644 1 +195 9346.260482139367 1 +276 3564.1046561513876 2 +277 3713.46266980025 16 +278 3981.4374288691265 52 diff --git a/reversing_game_mechanics/zoomlevel/win.size.all.filtered b/reversing_game_mechanics/zoomlevel/win.size.all.filtered new file mode 100644 index 0000000..b1abb5b --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.all.filtered @@ -0,0 +1,227 @@ +49 2120.5192760265113 245 +50 1969.829688069504 88 +51 1907.5106814904077 196 +56 2251.943604977709 106 +57 2004.575765592311 166 +58 2109.127781809343 362 +59 2126.4564420650613 137 +61 2173.5730951592127 58 +63 2232.8013794334684 39 +64 2133.3471353720192 71 +65 2239.5713875650404 100 +66 2259.5827048373335 868 +67 2240.224319125208 818 +68 2307.553032976707 443 +69 2226.5634956138124 579 +70 2356.425258734085 336 +71 2293.2538019155227 397 +72 2249.2098612623945 273 +73 2331.4519081465096 451 +74 2392.639755583778 300 +75 2404.2996901384818 277 +76 2403.8011565019265 161 +77 2357.5313359529287 262 +78 2377.4242364374095 157 +79 2339.8472172344927 145 +80 2438.0258407162137 228 +81 2488.3331770484433 301 +82 2489.7003835803216 352 +83 2499.0544211761376 291 +84 2455.6426857342253 304 +85 2498.9455776386967 154 +87 2474.5797623030867 702 +90 2515.553616999646 238 +91 2614.3163542310635 207 +92 2594.101771326638 66 +93 2544.643000501249 67 +94 2651.225377066235 95 +95 2681.96290056369 148 +96 2685.0344504307577 170 +97 2679.5546271722096 426 +98 2693.4938277263605 569 +99 2726.821592990638 54 +100 2696.036349903317 53 +101 2704.8558187082726 56 +102 2754.743726737571 88 +103 2719.114010114324 180 +104 2791.1581825471662 122 +105 2794.8023185907086 84 +106 2803.209767391659 133 +107 2805.824121358999 90 +108 2796.2517769328283 250 +109 2803.5384784232942 261 +110 2837.5144052497776 142 +111 2835.092414719492 107 +112 2846.737255174773 63 +113 2877.452345391666 63 +114 2851.5078467365297 53 +115 2780.2778638114573 113 +116 2891.1260781916794 242 +117 2870.733878296628 69 +118 2892.3390188565377 88 +122 2913.41998345587 61 +123 2955.795155283938 28 +125 3029.202205201891 67 +126 3015.162516349658 39 +127 3024.4353191959653 64 +128 3046.6238691377707 139 +129 3020.514029101669 40 +130 3015.3225366451265 112 +131 3021.6586504765887 92 +132 3040.8763539479864 73 +133 3065.0941257977706 58 +135 3026.624522467232 98 +136 3013.2540550043236 84 +140 3049.6730972351775 42 +148 3144.616033794905 7 +149 3228.400223020684 11 +150 3220.1863300125974 71 +151 3248.3468103021264 119 +152 3253.712494981694 66 +153 3238.846245192877 57 +154 3176.819950831334 43 +155 3301.4617974467005 36 +156 3296.8477368541 132 +157 3316.3596005258537 113 +158 3286.2537942161434 155 +92 2602.3854441646417 92 +93 2641.4407053727327 16 +95 2708.966592632696 50 +96 2712.70344859146 186 +97 2601.976556389392 122 +98 2696.738771182704 66 +99 2717.4488035655795 96 +100 2664.1535241047955 169 +101 2756.752618571351 135 +102 2690.486944774124 169 +103 2757.303936819443 122 +104 2788.0634856473407 455 +105 2799.2456126606685 442 +106 2824.3450568229086 140 +107 2810.7694676013543 170 +108 2763.8178304656767 344 +109 2737.670725269933 72 +110 2784.720632307665 251 +111 2785.9047004519016 159 +112 2875.0377388827437 260 +113 2811.6308434785674 181 +114 2870.785606763417 187 +115 2835.5659047181393 273 +116 2866.9461104108673 57 +117 2881.5004771819836 117 +118 2909.6427615774414 109 +120 2939.450458844306 263 +121 2906.4929038275664 204 +122 2948.7314221542797 121 +123 2953.9094434325502 74 +124 2985.440838469254 88 +125 2975.29695996887 115 +126 2954.414493601059 126 +128 2949.3024599047144 314 +130 2979.817444072707 119 +131 3028.992076582572 177 +133 3073.615623333536 128 +134 3060.4393475447278 151 +135 3086.498663534459 133 +137 3126.1601046651467 227 +139 3155.1700429612347 90 +140 3151.571195451564 231 +141 3164.168927222439 154 +142 3129.1259162903625 232 +144 3187.418077378617 219 +145 3138.7672739468912 97 +146 3195.2003067100504 89 +147 3194.6325297285757 158 +148 3195.955099809758 204 +149 3237.0166820700815 62 +150 3255.597180242052 127 +151 3254.93502239292 60 +152 3281.352160314403 73 +153 3279.3377380196753 125 +154 3255.6776560341473 152 +155 3271.2471627805808 279 +156 3247.845439672276 82 +157 3326.7739628655268 29 +159 3286.8233904485955 142 +160 3261.8871838247255 153 +161 3328.385344277312 44 +164 3295.002427920198 83 +165 3357.799874918099 76 +166 3378.6307877600357 39 +167 3370.5692397575813 30 +172 3422.502739224616 116 +173 3417.901402907931 66 +174 3439.523368142743 108 +177 3441.201679646225 19 +178 3409.1941863144143 224 +197 3560.370767209505 113 +200 3588.148547649609 76 +217 3755.401043830073 69 +219 3758.964219036941 85 +220 3790.129945001886 122 +221 3810.992521640524 172 +222 3792.3610060225014 23 +223 3815.631009413777 26 +224 3795.2923471058193 16 +225 3826.4825884877614 69 +226 3831.510668130783 54 +227 3832.1638795855274 156 +228 3833.123269606653 120 +229 3859.508388383163 141 +230 3830.84912258366 86 +141 3163.25923692637 7 +142 3149.401212929213 43 +143 3176.547339486695 42 +145 3126.600230282087 10 +146 3120.9783722416278 24 +147 3145.5927899205262 21 +158 3265.692269642074 28 +159 3282.8310952590905 6 +160 3261.3567728784287 5 +161 3274.0054978573266 11 +162 3332.2054258403696 15 +163 3361.016661666526 3 +164 3355.109089135553 14 +165 3373.971102425153 20 +169 3411.079741079062 17 +170 3398.256611852613 37 +171 3409.9420816195693 33 +172 3456.7860795831725 82 +173 3373.551392820332 8 +175 3430.284244782056 15 +176 3437.843510109208 76 +177 3458.1489268104115 281 +178 3477.0933263287598 38 +189 3489.3794577259723 114 +198 3590.769416155819 47 +174 3431.546152975361 6 +175 3497.8764986774477 14 +177 3389.6768282536905 36 +178 3468.8963662813567 13 +179 3485.865889560297 37 +180 3490.3886603070437 113 +181 3515.5905620535505 98 +182 3499.1920496023076 15 +195 3615.2654121101536 88 +196 3637.733635108541 62 +197 3628.236210612534 156 +198 3661.8806643581383 4 +199 3664.0061408245483 76 +200 3677.116261420082 12 +201 3637.3748775731106 146 +202 3685.892700554372 53 +203 3635.77777098656 56 +205 3716.556605246313 8 +206 3684.0620244507286 15 +207 3715.699799499416 30 +209 3690.992549437075 16 +215 3746.0168179013826 40 +216 3784.0027748404204 267 +217 3786.887112127849 70 +224 3824.525199289449 80 +225 3828.2075440080307 63 +226 3813.7278350716115 126 +227 3816.3041021386125 227 +229 3870.390807140798 48 +252 3995.193362028927 19 +253 3979.0382003695313 11 diff --git a/reversing_game_mechanics/zoomlevel/win.size.gnuplot b/reversing_game_mechanics/zoomlevel/win.size.gnuplot new file mode 100644 index 0000000..90886c3 --- /dev/null +++ b/reversing_game_mechanics/zoomlevel/win.size.gnuplot @@ -0,0 +1,16 @@ +min(a,b)=(ab)?a:b + +f(x) = a* x**b +fit f(x) "win.size.all.filtered" using 1:2 via a,b + +plot "win.size.1" using 1:2:(min(1,$3/100)) lt rgb "red" pt 2 ps variable, \ + "win.size.2" using 1:2:(min(1,$3/100)) lt rgb "blue" pt 2 ps variable, \ + "win.size.3" using 1:2:(min(1,$3/100)) lt rgb "green" pt 2 ps variable, \ + "win.size.4" using 1:2:(1) lt rgb "purple" pt 2 ps variable, \ + "win.size.5" using 1:2:(1) lt rgb "cyan" pt 2 ps variable, \ + "win.size.6" using 1:2:(1) lt rgb "orange" pt 2 ps variable, \ + x**0.4*460+50 lt rgb "gray", \ + x**0.407*460-400 lt rgb "gray", \ + f(x) lt rgb "black" +pause -1 diff --git a/stats.py b/stats.py index 6744d0b..0b460c5 100644 --- a/stats.py +++ b/stats.py @@ -190,12 +190,12 @@ class Stats: maxwidth = quantile(sorted(map(lambda x:x[0], rects)), 0.75) maxheight = quantile(sorted(map(lambda x:x[1], rects)), 0.75) - if (math.sqrt(maxwidth**2+maxheight**2) < 4000): + if math.sqrt(maxwidth**2+maxheight**2) < 4000: # TODO FIXME svw[size] = (maxwidth,maxheight) ratios += [maxwidth/maxheight] - if verbose: print(str(size)+"\t"+str(math.sqrt(maxwidth**2+maxheight**2))) + if verbose: print(str(size)+"\t"+str(math.sqrt(maxwidth**2+maxheight**2))+"\t\t"+str(len(rects))) print ("median ratio = "+str(quantile(sorted(ratios),0.5))) -- cgit v1.2.3 From 38f85429d76bb220580283c638036cbbf67df4df Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Thu, 27 Aug 2015 21:06:03 +0200 Subject: fix --- reversing_game_mechanics/zoomlevel/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reversing_game_mechanics/zoomlevel/README b/reversing_game_mechanics/zoomlevel/README index 72cd14d..7845ea3 100644 --- a/reversing_game_mechanics/zoomlevel/README +++ b/reversing_game_mechanics/zoomlevel/README @@ -4,7 +4,7 @@ dunno. Data collected using bea9a124317, on 2015-08-25 *iirc*. (-> stats.pickle.xz) -Data analyzed using a973a898619, with: +Data analyzed using ea4515d0516, with: python analyze.py stats.pickle > temp -- cgit v1.2.3 From f13b8a44441206a4f761002ed3adabd129601ba1 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Fri, 28 Aug 2015 00:29:04 +0200 Subject: use new zoom formula --- game_mechanics.txt | 1 + gui.py | 47 +++++++++++++++++++--- mechanics.py | 3 ++ reversing_game_mechanics/zoomlevel/README | 2 + reversing_game_mechanics/zoomlevel/fit.log | 46 --------------------- .../zoomlevel/win.size.gnuplot | 5 ++- 6 files changed, 51 insertions(+), 53 deletions(-) delete mode 100644 reversing_game_mechanics/zoomlevel/fit.log diff --git a/game_mechanics.txt b/game_mechanics.txt index 1bb5987..9c64805 100644 --- a/game_mechanics.txt +++ b/game_mechanics.txt @@ -5,3 +5,4 @@ can eat ejected mass if mass >= 18 i.e. size >= 43 cell can eat us, if their size/mass(??) is at least 1.25* our size/mass +zoom level is 369.399 * sum(own_cells.size) ** 0.431776 diff --git a/gui.py b/gui.py index ed5c9d3..f4654ef 100644 --- a/gui.py +++ b/gui.py @@ -6,6 +6,7 @@ from pygame.locals import * import sys import math import time +import mechanics from agarnet.agarnet.vec import Vec running = True @@ -136,12 +137,31 @@ def draw_text(pos, text, color, font_size=16, global_coords=True, draw_centered= def update(): pygame.display.update() -def calc_zoom(): - zoom1 = screensize[0] / 2051. - zoom2 = screensize[1] / 1216. - return max(zoom1,zoom2) +def update_zoom(): + global zoom + global calculated_visible_width, calculated_visible_height + + ratio = 1.7 # reverse engineered value. + + size = sum(map(lambda cell : cell.size, c.player.own_cells)) + + # reverse engineered formula + diag_server = mechanics.viewport_diag(size) if size > 0 else 10000 + + # calculate screen diag, if we would have a screen with our width, but correct ratio + diag1 = math.sqrt(screensize[0]**2 * (1 + 1/1.7**2)) + # calculate screen diag, if we would have a screen with our height, but correct ratio + diag2 = math.sqrt(screensize[1]**2 * (1 + 1.7**2)) + + # what we expect to be visible from server + calculated_visible_width = diag_server / math.sqrt(1+1/ratio**2) + calculated_visible_height = diag_server / math.sqrt(1+ ratio**2) + + zoom1 = screensize[0] / calculated_visible_width + zoom2 = screensize[1] / calculated_visible_height + + zoom = min(zoom1,zoom2) / 2 -zoom = calc_zoom() def world_to_win_length(l): return int(l*zoom) @@ -238,6 +258,19 @@ def draw_leaderboard(): # screen.blit(surface, (5, next_y)) next_y += surface.get_height()+5 +def draw_visible_window_borders(): + global screen + + vignette_color=(192,192,192) + vignette_width = int(max(0, (screensize[0]-world_to_win_length(calculated_visible_width))/2)) + vignette_height = int(max(0, (screensize[1]-world_to_win_length(calculated_visible_height))/2)) + + screen.fill(vignette_color, rect=((0,0),(vignette_width,screensize[1]))) + screen.fill(vignette_color, rect=((screensize[0]-vignette_width,0),(vignette_width,screensize[1]))) + screen.fill(vignette_color, rect=((0,0),(screensize[0],vignette_height))) + screen.fill(vignette_color, rect=((0,screensize[1]-vignette_height),(screensize[0],vignette_height))) + + def draw_world_borders(): top = int((c.world.top_left[0] - c.player.center[1])*zoom + screensize[1]/2) left = int((c.world.top_left[1] - c.player.center[0])*zoom + screensize[0]/2) @@ -291,8 +324,10 @@ def draw_frame(): pygame.event.pump() clock.tick() + update_zoom() clear_screen() + draw_visible_window_borders() draw_world_borders() food = list(filter(lambda x: x.is_food, c.world.cells.values())) @@ -327,7 +362,7 @@ def draw_frame(): if event.type == VIDEORESIZE: screensize = event.dict['size'] screen=pygame.display.set_mode(screensize, HWSURFACE|DOUBLEBUF|RESIZABLE) - zoom = calc_zoom() + update_zoom() pygame.display.update() if event.type == QUIT: pygame.display.quit() diff --git a/mechanics.py b/mechanics.py index d242493..1f9d5cc 100644 --- a/mechanics.py +++ b/mechanics.py @@ -1,3 +1,6 @@ def speed(size): return 86 / (size**0.45) +def viewport_diag(sizesum): + return 370 * max(sizesum,70)**0.431776 + diff --git a/reversing_game_mechanics/zoomlevel/README b/reversing_game_mechanics/zoomlevel/README index 7845ea3..a2acc90 100644 --- a/reversing_game_mechanics/zoomlevel/README +++ b/reversing_game_mechanics/zoomlevel/README @@ -28,3 +28,5 @@ Result: visible diagonal = 369.399 * sum(sizes)**0.431776 Also, analyze.py tells us that the viewport ratio is 1.7 : 1 +Additionally, if size<70, then the value 70 instead of "size" is used (found +out by tinkering around manually) diff --git a/reversing_game_mechanics/zoomlevel/fit.log b/reversing_game_mechanics/zoomlevel/fit.log deleted file mode 100644 index 10e4639..0000000 --- a/reversing_game_mechanics/zoomlevel/fit.log +++ /dev/null @@ -1,46 +0,0 @@ - - -******************************************************************************* -Thu Aug 27 21:04:27 2015 - - -FIT: data read from "win.size.all.filtered" using 1:2 - format = x:z - #datapoints = 227 - residuals are weighted equally (unit weight) - -function used for fitting: f(x) -fitted parameters initialized with current variable values - - - - Iteration 0 - WSSR : 1.99006e+09 delta(WSSR)/WSSR : 0 - delta(WSSR) : 0 limit for stopping : 1e-05 - lambda : 543.709 - -initial set of free parameter values - -a = 1 -b = 1 - -After 187 iterations the fit converged. -final sum of squares of residuals : 316175 -rel. change during last iteration : -9.20903e-11 - -degrees of freedom (FIT_NDF) : 225 -rms of residuals (FIT_STDFIT) = sqrt(WSSR/ndf) : 37.4863 -variance of residuals (reduced chisquare) = WSSR/ndf : 1405.22 - -Final set of parameters Asymptotic Standard Error -======================= ========================== - -a = 369.399 +/- 4.401 (1.191%) -b = 0.431776 +/- 0.002383 (0.5519%) - - -correlation matrix of the fit parameters: - - a b -a 1.000 -b -0.998 1.000 diff --git a/reversing_game_mechanics/zoomlevel/win.size.gnuplot b/reversing_game_mechanics/zoomlevel/win.size.gnuplot index 90886c3..aa5499c 100644 --- a/reversing_game_mechanics/zoomlevel/win.size.gnuplot +++ b/reversing_game_mechanics/zoomlevel/win.size.gnuplot @@ -2,7 +2,9 @@ min(a,b)=(ab)?a:b f(x) = a* x**b +g(x) = aa* x**bb + cc fit f(x) "win.size.all.filtered" using 1:2 via a,b +fit g(x) "win.size.all.filtered" using 1:2 via aa,bb,cc plot "win.size.1" using 1:2:(min(1,$3/100)) lt rgb "red" pt 2 ps variable, \ "win.size.2" using 1:2:(min(1,$3/100)) lt rgb "blue" pt 2 ps variable, \ @@ -12,5 +14,6 @@ plot "win.size.1" using 1:2:(min(1,$3/100)) lt rgb "red" pt 2 ps variable, \ "win.size.6" using 1:2:(1) lt rgb "orange" pt 2 ps variable, \ x**0.4*460+50 lt rgb "gray", \ x**0.407*460-400 lt rgb "gray", \ - f(x) lt rgb "black" + f(x) lt rgb "black", \ + g(x) lt rgb "black" pause -1 -- cgit v1.2.3 From 403058ba1e31330689f9b36a10384ee0b2e8ebde Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Fri, 28 Aug 2015 14:19:22 +0200 Subject: hopefully fixed "enemy in our midpoint" issue --- strategy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/strategy.py b/strategy.py index 2ea84e2..1a57897 100644 --- a/strategy.py +++ b/strategy.py @@ -196,11 +196,12 @@ class Strategy: if ( (not cell.is_virus and dist < ((500+2*cell.size) if cell.mass > 1.25*my_smallest.mass*2 else (300+cell.size)) and cell.mass > 1.25 * my_smallest.mass) or (cell.is_virus and dist < my_largest.mass and cell.mass < my_largest.mass) ) and not (cell in friendly_cells) or (cell in friendly_cells) and dist < cell.size+10: try: angle = math.atan2(relpos[1],relpos[0]) - corridor_halfwidth = math.asin(cell.size / dist) + corridor_halfwidth = math.asin(min(1, cell.size / dist)) forbidden_intervals += canonicalize_angle_interval((angle-corridor_halfwidth, angle+corridor_halfwidth)) 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): -- cgit v1.2.3 From 024a2e35638436dd36379d86f1619b617c2ecea9 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Fri, 28 Aug 2015 16:26:52 +0200 Subject: user-settable vignette --- gui.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gui.py b/gui.py index f4654ef..83730bf 100644 --- a/gui.py +++ b/gui.py @@ -33,6 +33,15 @@ marker_updated = [True, True, True] screensize=(1280, 800) screen=pygame.display.set_mode(screensize,HWSURFACE|DOUBLEBUF|RESIZABLE) +vignette = 1. + +def enable_vignette(factor=0.15): + global vignette + if factor: + vignette = 1+factor + else: + vignette = 1 + def draw_bar(rect, val, thresh=None, min=0, max=1, color=(0,0,0), barcolor=None, exceedcolor=(255,0,0), threshcolor=None): v = (val-min)/(max-min) t = (thresh-min)/(max-min) @@ -160,7 +169,7 @@ def update_zoom(): zoom1 = screensize[0] / calculated_visible_width zoom2 = screensize[1] / calculated_visible_height - zoom = min(zoom1,zoom2) / 2 + zoom = min(zoom1,zoom2) / vignette def world_to_win_length(l): -- cgit v1.2.3 From e4b732abd4ea034f75645d333ff5b357d1b612e7 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Fri, 28 Aug 2015 17:27:42 +0200 Subject: track shooting angles and distances --- gui.py | 2 +- stats.py | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- strategy.py | 1 - subscriber.py | 32 +++++++++++++------- 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 + -- cgit v1.2.3 From fd66690aa9c2dc429325891c906b97d5184bc5e0 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Fri, 28 Aug 2015 18:57:00 +0200 Subject: analyzing functions --- analyze.py | 5 ++++- stats.py | 19 ++++++++++++++++--- strategy.py | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/analyze.py b/analyze.py index 1720719..520b3b0 100644 --- a/analyze.py +++ b/analyze.py @@ -14,4 +14,7 @@ for f in files[1:]: s.analyze_speed() print("\n" + "-"*40 + "\n") s.analyze_visible_window(True) - +for i in ["split cell", "ejected mass", "virus"]: + s.analyze_deviations(i) +for i in ["split cell", "ejected mass", "virus"]: + s.analyze_distances(i) diff --git a/stats.py b/stats.py index a136ca9..b567800 100644 --- a/stats.py +++ b/stats.py @@ -297,7 +297,20 @@ class Stats: 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)) + try: + mean, stddev = fit_gaussian(ds) + except: + mean, stddev = "???", "???" + + print(celltype+" eject/split direction deviations: mean = "+str(mean)+", stddev="+str(stddev)+", ndata="+str(len(ds))) + + def analyze_distances(self, celltype): + ds = [v[0] for v in self.data.eject_distlogs[celltype]] + + try: + mean, stddev = fit_gaussian(ds) + except: + mean, stddev = "???", "???" + + print(celltype+" eject/split distances: mean = "+str(mean)+", stddev="+str(stddev)+", ndata="+str(len(ds))) diff --git a/strategy.py b/strategy.py index 1be22cf..21a06cf 100644 --- a/strategy.py +++ b/strategy.py @@ -164,7 +164,7 @@ class Strategy: except AttributeError: print("cannot calculate shoot angle, too few backlog") continue - # check if ejecting mass would feed one friend + # check if ejecting mass would feed a friend possibly_feedable_cells = list(filter(lambda c : can_feed(my_cell, c), self.c.world.cells.values())) possibly_feedable_cells.sort(key = lambda c : (my_cell.pos - c.pos).len()) -- cgit v1.2.3 From 8b2d517c91eac25234894c2969e3b7d792bcd838 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Fri, 28 Aug 2015 19:02:06 +0200 Subject: forgot to commit geometry.py, oops --- geometry.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 geometry.py diff --git a/geometry.py b/geometry.py new file mode 100644 index 0000000..d69add8 --- /dev/null +++ b/geometry.py @@ -0,0 +1,27 @@ +import math +def distance_point_line(p, l1, l2): + # (x - l1.x) * (l2.y-l1.y)/(l2.x-l1.x) + l1.y = y + # x * (l2.y-l1.y)/(l2.x-l1.x) - l1.x * (l2.y-l1.y)/(l2.x-l1.x) + l1.y - y = 0 + # x * (l2.y-l1.y) - l1.x * (l2.y-l1.y) + l1.y * (l2.x-l1.x) - y * (l2.x-l1.x) = 0 + # ax + by + c = 0 + # with a = (l2.y-l1.y), b = -(l2.x-l1.x), c = l1.y * (l2.x-l1.x) - l1.x * (l2.y-l1.y) + a = (l2.y-l1.y) + b = -(l2.x-l1.x) + c = l1.y * (l2.x-l1.x) - l1.x * (l2.y-l1.y) + + d = math.sqrt(a**2 + b**2) + a/=d + b/=d + c/=d + + assert (abs(a*l1.x + b*l1.y + c) < 0.001) + assert (abs(a*l2.x + b*l2.y + c) < 0.001) + + return abs(a*p.x + b*p.y + c) + +def is_colinear(points, epsilon=1): + for point in points: + if distance_point_line(point, points[0], points[-1]) > epsilon: + return False + return True + -- cgit v1.2.3 From 165dd4185804718ca874a84960f1eb66a8c6c4cb Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sat, 29 Aug 2015 01:44:20 +0200 Subject: better analyzing magic for ejects/splits --- analyze.py | 3 ++- stats.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/analyze.py b/analyze.py index 520b3b0..0477583 100644 --- a/analyze.py +++ b/analyze.py @@ -13,8 +13,9 @@ for f in files[1:]: s.analyze_speed() print("\n" + "-"*40 + "\n") -s.analyze_visible_window(True) +#s.analyze_visible_window(True) for i in ["split cell", "ejected mass", "virus"]: s.analyze_deviations(i) +print("") for i in ["split cell", "ejected mass", "virus"]: s.analyze_distances(i) diff --git a/stats.py b/stats.py index b567800..e65c49b 100644 --- a/stats.py +++ b/stats.py @@ -19,7 +19,19 @@ def quantile(values, q): if isinstance(values, dict): return quantile(flatten(map(lambda x : [x[0]]*x[1], sorted(values.items(),key=lambda x:x[0]))), q) else: - return values[ int(len(values)*q) ] + try: + return sorted(values)[ int(len(values)*q) ] + except: + return 0 + +def find_smallest_q_confidence_area(values, q): + try: + mid = min(values, key = lambda value : quantile(list(map(lambda x : abs(x-value), values)), q)) + deviation = quantile(list(map(lambda x : abs(x-mid), values)),q) + #print(list(map(lambda x : abs(x-mid), values))) + return mid,deviation + except: + return 0,0 def avg(values): if not isinstance(values, dict): @@ -220,6 +232,12 @@ class Stats: for j in data2.size_vs_speed[i]: self.data.size_vs_speed[i][j] += data2.size_vs_speed[i][j] + for i in data2.eject_deviations: + self.data.eject_deviations[i] += data2.eject_deviations[i] + + for i in data2.eject_distlogs: + self.data.eject_distlogs[i] += data2.eject_distlogs[i] + def analyze_speed(self): @@ -289,11 +307,13 @@ class Stats: def analyze_visible_window(self, verbose=False): for ncells in sorted(self.data.size_vs_visible_window.keys()): - print("\nwith "+str(ncells)+" cells, depending on sum(size)") - self.analyze_visible_window_helper(self.data.size_vs_visible_window[ncells], verbose) + if len(self.data.size_vs_visible_window[ncells]) > 0: + print("\nwith "+str(ncells)+" cells, depending on sum(size)") + self.analyze_visible_window_helper(self.data.size_vs_visible_window[ncells], verbose) 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) + if len(self.data.mass_vs_visible_window[ncells]) > 0: + 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] @@ -303,7 +323,18 @@ class Stats: except: mean, stddev = "???", "???" + + quant = quantile(list(map(abs, ds)), 0.75) + print(celltype+" eject/split direction deviations: mean = "+str(mean)+", stddev="+str(stddev)+", ndata="+str(len(ds))) + print("\t75%% of the splits had a deviation smaller than %.2f rad = %.2f deg" % (quant, quant*180/math.pi)) + print("") + + + #a,b = numpy.histogram(ds, bins=100) + #midpoints = map(lambda x : (x[0]+x[1])/2, zip(b, b[1:])) + #for n,x in zip(a,midpoints): + # print(str(n) + "\t" + str(x)) def analyze_distances(self, celltype): ds = [v[0] for v in self.data.eject_distlogs[celltype]] @@ -314,3 +345,18 @@ class Stats: mean, stddev = "???", "???" print(celltype+" eject/split distances: mean = "+str(mean)+", stddev="+str(stddev)+", ndata="+str(len(ds))) + + #a,b = numpy.histogram(ds, bins=100) + #midpoints = list(map(lambda x : (x[0]+x[1])/2, zip(b, b[1:]))) + #for n,x in zip(a,midpoints): + # print(str(n) + "\t" + str(x)) + + #maxidx = max(range(0,len(a)), key = lambda i : a[i]) + #print("\tmaximum at "+str(midpoints[maxidx])) + + #q = 75 if celltype == "ejected mass" else 75 + #quant = quantile(list(map(lambda v : abs(v-midpoints[maxidx]), ds)), q/100) + #print("\t"+str(q)+"% of values lie have a distance of at most "+str(quant)+" from the maximum") + + print("\t75%% of the values lie in the interval %.2f plusminus %.2f" % find_smallest_q_confidence_area(ds, 0.75)) + print("") -- cgit v1.2.3 From 3741d3bb804542f7e994763ed2f2ebabe56bd5eb Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sat, 29 Aug 2015 01:55:16 +0200 Subject: reversing_game_mechanics/splits_and_ejects/README --- reversing_game_mechanics/splits_and_ejects/README | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 reversing_game_mechanics/splits_and_ejects/README diff --git a/reversing_game_mechanics/splits_and_ejects/README b/reversing_game_mechanics/splits_and_ejects/README new file mode 100644 index 0000000..6e33969 --- /dev/null +++ b/reversing_game_mechanics/splits_and_ejects/README @@ -0,0 +1,16 @@ +Data collected with revision 165dd41, four parallel instances, 30-45 minutes each. +Analyzed with analyze.py + +split cell eject/split direction deviations: mean = -0.04179961392956227, stddev=0.4556678701725402, ndata=159 + 75% of the splits had a deviation smaller than 0.02 rad = 1.31 deg + +ejected mass eject/split direction deviations: mean = -0.0016847086620534303, stddev=0.872858965604425, ndata=352 + 75% of the splits had a deviation smaller than 0.46 rad = 26.47 deg + + +split cell eject/split distances: mean = 388.2279635920042, stddev=222.71465106976927, ndata=314 + 75% of the values lie in the interval 381.25 plusminus 225.53 + +ejected mass eject/split distances: mean = 442.90229450857305, stddev=189.2221703217239, ndata=252 + 75% of the values lie in the interval 535.71 plusminus 8.61 + -- cgit v1.2.3 From 07fde40a846f11d123ddc2ccf182e417c561931a Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sat, 29 Aug 2015 01:55:42 +0200 Subject: stuff --- gui.py | 4 ++-- stats.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gui.py b/gui.py index 26b1045..1d7e312 100644 --- a/gui.py +++ b/gui.py @@ -206,8 +206,8 @@ def draw_cell(cell): cx,cy = world_to_win_pt(cell.pos,c.player.center) try: mov_ang = cell.movement_angle - p2 = cell.pos + Vec( math.cos(mov_ang + 10*math.pi/180), math.sin(mov_ang + 10*math.pi/180) ) * (cell.size+700) - p3 = cell.pos + Vec( math.cos(mov_ang - 10*math.pi/180), math.sin(mov_ang - 10*math.pi/180) ) * (cell.size+700) + p2 = cell.pos + Vec( math.cos(mov_ang + 26*math.pi/180), math.sin(mov_ang + 26*math.pi/180) ) * (cell.size+700) + p3 = cell.pos + Vec( math.cos(mov_ang - 26*math.pi/180), math.sin(mov_ang - 26*math.pi/180) ) * (cell.size+700) cx2,cy2 = world_to_win_pt(p2,c.player.center) cx3,cy3 = world_to_win_pt(p3,c.player.center) diff --git a/stats.py b/stats.py index e65c49b..bb88c3e 100644 --- a/stats.py +++ b/stats.py @@ -6,6 +6,7 @@ import pickle from functools import reduce import mechanics import geometry +#import numpy def fit_gaussian(l): mean = sum(l) / len(l) -- cgit v1.2.3 From 24fd1057a1b78715e6bd3038754dfb62efe4f369 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sat, 29 Aug 2015 02:03:06 +0200 Subject: . --- reversing_game_mechanics/splits_and_ejects/README | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/reversing_game_mechanics/splits_and_ejects/README b/reversing_game_mechanics/splits_and_ejects/README index 6e33969..d8a68e6 100644 --- a/reversing_game_mechanics/splits_and_ejects/README +++ b/reversing_game_mechanics/splits_and_ejects/README @@ -14,3 +14,37 @@ split cell eject/split distances: mean = 388.2279635920042, stddev=222.714651069 ejected mass eject/split distances: mean = 442.90229450857305, stddev=189.2221703217239, ndata=252 75% of the values lie in the interval 535.71 plusminus 8.61 +distances are measured between "spawn point of cell" and "end point of movement". +Spawnpoint is usually near "parentcell.midpoint + parentcell.size". + + + +Now if we measure distances between "midpoint of parent cell" and "end point of movement" by +applying the following patch: + +diff --git a/stats.py b/stats.py +index bb88c3e..1c0a196 100644 +--- a/stats.py ++++ b/stats.py +@@ -338,7 +338,7 @@ class Stats: + # print(str(n) + "\t" + str(x)) + + def analyze_distances(self, celltype): +- ds = [v[0] for v in self.data.eject_distlogs[celltype]] ++ ds = [v[1] for v in self.data.eject_distlogs[celltype]] + + try: + mean, stddev = fit_gaussian(ds) + +we get this: + +split cell eject/split distances: mean = 560.4528176561469, stddev=276.25260008531626, ndata=314 + 75% of the values lie in the interval 556.62 plusminus 322.76 + +ejected mass eject/split distances: mean = 767.2502438544719, stddev=168.80422060053823, ndata=252 + 75% of the values lie in the interval 732.30 plusminus 86.28 + + +As one can see, the "plusminus" values are much larger than above. So measuring between "spawnpoint" and +"endpoint" is more appropriate. + -- cgit v1.2.3 From 87ed12e22d6319ad43bfb11a6da1ded39d7ba74e Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sat, 29 Aug 2015 02:03:44 +0200 Subject: . --- reversing_game_mechanics/splits_and_ejects/README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reversing_game_mechanics/splits_and_ejects/README b/reversing_game_mechanics/splits_and_ejects/README index d8a68e6..14fa5ad 100644 --- a/reversing_game_mechanics/splits_and_ejects/README +++ b/reversing_game_mechanics/splits_and_ejects/README @@ -1,5 +1,5 @@ -Data collected with revision 165dd41, four parallel instances, 30-45 minutes each. -Analyzed with analyze.py +Data collected with revision 165dd41, four parallel instances, 30-45 minutes each, on +2015-08-28. Analyzed with analyze.py split cell eject/split direction deviations: mean = -0.04179961392956227, stddev=0.4556678701725402, ndata=159 75% of the splits had a deviation smaller than 0.02 rad = 1.31 deg -- cgit v1.2.3 From f88995ed18fa57ddb7ce7b00003e025f67d0db11 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 30 Aug 2015 17:19:41 +0200 Subject: collect more data --- gui.py | 1 + stats.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- subscriber.py | 7 +++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/gui.py b/gui.py index 1d7e312..6ba6f36 100644 --- a/gui.py +++ b/gui.py @@ -245,6 +245,7 @@ def draw_cell(cell): font_size = 16 draw_text((cx, cy + radius + 10), cell.name, (0, 0, 0), font_size, False, True) + draw_text((cx, cy + radius + 10 + font_size), str(cell.cid), (0,0,0), font_size, False, True) # surface = draw_text(cell.name, (0, 0, 0), font_size) # screen.blit(surface, (cx - (surface.get_width()/2), cy + radius + 5)) diff --git a/stats.py b/stats.py index bb88c3e..9bf834a 100644 --- a/stats.py +++ b/stats.py @@ -63,6 +63,16 @@ def return_zero(): def return_defaultdict_with_zeros(): return defaultdict(return_zero) +class ReMerging: + def __init__(self, size1, size2, birth1, birth2, is_parent_child, begin_time): + self.size1 = size1 + self.size2 = size2 + self.birth1 = birth1 + self.birth2 = birth2 + self.is_parent_child = is_parent_child + self.begin_time = begin_time + self.end_time = None + class Stats: def __init__(self,c,data=None): self.c = c @@ -71,7 +81,7 @@ class Stats: if data == None: self.data = StatData() - self.data.version = 3 + self.data.version = 4 self.data.min_mass = 0 self.data.max_mass = 0 @@ -89,6 +99,9 @@ class Stats: self.data.eject_distlogs = {"virus" : [], "split cell" : [], "ejected mass" : []} self.data.eject_deviations = {"virus" : [], "split cell" : [], "ejected mass" : []} + + self.data.observed_virus_sizes = defaultdict(return_zero) + self.data.remerging = {} else: self.data = data @@ -158,6 +171,30 @@ class Stats: self.data.mass_vs_visible_window[n_own_cells][own_total_mass].append((visible_width,visible_height)) + # log virus sizes + for cell in cells: + if cell.is_virus: + self.data.observed_virus_sizes[cell.size] += 1 + + # detect re-merging cells + for cell in own_cells: + for cell2 in own_cells: + if cell2 != cell: + dist = (cell.pos - cell2.pos).len() + expected_dist = cell.size + cell2.size + min_dist = max(cell.size, cell2.size) + + if (dist < (0.9 * expected_dist + 0.1 * min_dist)): + is_parent_child = (cell == cell2.parent or cell2 == cell.parent) + print("cells seem to be merging! they are "+ ("" if is_parent_child else "NOT ") + "parent and child") + pair_id = (min(cell.cid,cell2.cid), max(cell.cid,cell2.cid)) + + if pair_id not in self.data.remerging: + self.data.remerging[pair_id] = ReMerging(cell.size, cell2.size, cell.spawntime, cell2.spawntime, is_parent_child, self.c.world.time) + else: + self.data.remerging[pair_id].end_time = self.c.world.time + + # find ejected mass, split cells or viruses that have come to rest for cell in cells: @@ -184,11 +221,18 @@ class Stats: cell.calmed_down = True # TODO: speed log + # distance is calculated naively distance = (cell.spawnpoint - cell.pos).len() + + # distance2 is calculated along the cell's path (will differ if the flight was not colinear) + poslog = list(cell.poslog) + speeds = list(map(lambda vecs : (vecs[0]-vecs[1]).len(), zip(poslog, poslog[1:]))) + distance2 = sum(speeds) + 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)) + self.data.eject_distlogs[celltype] += [(distance, distance2, distance_from_parent, cell.parentsize_when_spawned, len(cell.poslog), speeds)] + print(" flown distance = %.2f / %.2f"%(distance,distance2)) if len(cell.poslog) == 5: # calculate movement direction from the first 5 samples @@ -284,7 +328,7 @@ class Stats: maxheight = quantile(sorted(map(lambda x:x[1], rects)), 0.75) if math.sqrt(maxwidth**2+maxheight**2) < 4000: - # TODO FIXME + # TODO FIXME svw[size] = (maxwidth,maxheight) ratios += [maxwidth/maxheight] diff --git a/subscriber.py b/subscriber.py index cedee99..483ae04 100644 --- a/subscriber.py +++ b/subscriber.py @@ -81,11 +81,14 @@ class EnhancingSubscriber(DummySubscriber): def __init__(self): self.c = None self.history = {} + self.time = 0 def set_client(self,c): self.c = c def on_world_update_post(self): + self.c.world.time = self.time + self.time += 1 # create and purge poslog history, movement and movement_angle for cid in self.history: @@ -105,6 +108,10 @@ class EnhancingSubscriber(DummySubscriber): for cid in self.c.world.cells: cell = self.c.world.cells[cid] + + if not hasattr(cell, "spawntime"): + cell.spawntime = self.c.world.time + try: oldpos = cell.poslog[-3-1] cell.movement = (cell.pos - oldpos)/3 -- cgit v1.2.3 From 4c1be522f6eddf7b36600119cfddf1c75b995864 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 30 Aug 2015 18:08:04 +0200 Subject: moved stuff around, no changes --- stats.py | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/stats.py b/stats.py index 9bf834a..a10ea1d 100644 --- a/stats.py +++ b/stats.py @@ -105,6 +105,34 @@ class Stats: else: self.data = data + def save(self,filename): + pickle.dump(self.data, open(filename,"wb")) + + def load(filename): + return Stats(None, pickle.load(open(filename,"rb"))) + + def merge(self, filename): + data2 = pickle.load(open(filename,"rb")) + self.data.min_mass = min(self.data.min_mass, data2.min_mass) + self.data.max_mass = max(self.data.max_mass, data2.max_mass) + + for i in data2.size_vs_visible_window: + for j in data2.size_vs_visible_window[i]: + self.data.size_vs_visible_window[i][j] += data2.size_vs_visible_window[i][j] + for i in data2.mass_vs_visible_window: + for j in data2.mass_vs_visible_window[i]: + self.data.mass_vs_visible_window[i][j] += data2.mass_vs_visible_window[i][j] + + for i in data2.size_vs_speed: + for j in data2.size_vs_speed[i]: + self.data.size_vs_speed[i][j] += data2.size_vs_speed[i][j] + + for i in data2.eject_deviations: + self.data.eject_deviations[i] += data2.eject_deviations[i] + + for i in data2.eject_distlogs: + self.data.eject_distlogs[i] += data2.eject_distlogs[i] + def log_mass(self, mass): self.data.mass_history.append((time.time(), mass)) self.data.current_mass = mass @@ -255,34 +283,6 @@ class Stats: else: print(celltype+" did NOT fly in a straight line, ignoring...") - def save(self,filename): - pickle.dump(self.data, open(filename,"wb")) - - def load(filename): - return Stats(None, pickle.load(open(filename,"rb"))) - - def merge(self, filename): - data2 = pickle.load(open(filename,"rb")) - self.data.min_mass = min(self.data.min_mass, data2.min_mass) - self.data.max_mass = max(self.data.max_mass, data2.max_mass) - - for i in data2.size_vs_visible_window: - for j in data2.size_vs_visible_window[i]: - self.data.size_vs_visible_window[i][j] += data2.size_vs_visible_window[i][j] - for i in data2.mass_vs_visible_window: - for j in data2.mass_vs_visible_window[i]: - self.data.mass_vs_visible_window[i][j] += data2.mass_vs_visible_window[i][j] - - for i in data2.size_vs_speed: - for j in data2.size_vs_speed[i]: - self.data.size_vs_speed[i][j] += data2.size_vs_speed[i][j] - - for i in data2.eject_deviations: - self.data.eject_deviations[i] += data2.eject_deviations[i] - - for i in data2.eject_distlogs: - self.data.eject_distlogs[i] += data2.eject_distlogs[i] - def analyze_speed(self): -- cgit v1.2.3 From c3623e098edce070b6e89f2c71638cec2efdd694 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 30 Aug 2015 18:11:52 +0200 Subject: updated Stats.merge() --- stats.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stats.py b/stats.py index a10ea1d..4827d8a 100644 --- a/stats.py +++ b/stats.py @@ -133,6 +133,11 @@ class Stats: for i in data2.eject_distlogs: self.data.eject_distlogs[i] += data2.eject_distlogs[i] + for i in self.data.observed_virus_sizes: + self.data.observed_virus_sizes[i] += data2.observed_virus_sizes[i] + + self.data.remerging.update(data2.remerging) + def log_mass(self, mass): self.data.mass_history.append((time.time(), mass)) self.data.current_mass = mass -- cgit v1.2.3 From c383083c3e41ae252f8e66d0b13795c5536b7b01 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 30 Aug 2015 21:08:57 +0200 Subject: analyze_{virus_sizes,remerge}() functions --- analyze.py | 5 ++++- stats.py | 22 ++++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/analyze.py b/analyze.py index 0477583..a0537f7 100644 --- a/analyze.py +++ b/analyze.py @@ -11,7 +11,7 @@ s = Stats.load(files[0]) for f in files[1:]: s.merge(f) -s.analyze_speed() +#s.analyze_speed() print("\n" + "-"*40 + "\n") #s.analyze_visible_window(True) for i in ["split cell", "ejected mass", "virus"]: @@ -19,3 +19,6 @@ for i in ["split cell", "ejected mass", "virus"]: print("") for i in ["split cell", "ejected mass", "virus"]: s.analyze_distances(i) + +s.analyze_virus_sizes() +s.analyze_remerge() diff --git a/stats.py b/stats.py index 4827d8a..42ee0ea 100644 --- a/stats.py +++ b/stats.py @@ -388,13 +388,17 @@ class Stats: def analyze_distances(self, celltype): ds = [v[0] for v in self.data.eject_distlogs[celltype]] + ns = [v[4] for v in self.data.eject_distlogs[celltype]] try: mean, stddev = fit_gaussian(ds) + meann, stddevn = fit_gaussian(ns) except: mean, stddev = "???", "???" + meann, stddevn = "???", "???" - print(celltype+" eject/split distances: mean = "+str(mean)+", stddev="+str(stddev)+", ndata="+str(len(ds))) + print(celltype+" eject/split distances: mean = "+str(mean) +", stddev ="+str(stddev) +", ndata="+str(len(ds))) + print(celltype+" meann = "+str(meann)+", stddevn ="+str(stddevn)) #a,b = numpy.histogram(ds, bins=100) #midpoints = list(map(lambda x : (x[0]+x[1])/2, zip(b, b[1:]))) @@ -408,5 +412,19 @@ class Stats: #quant = quantile(list(map(lambda v : abs(v-midpoints[maxidx]), ds)), q/100) #print("\t"+str(q)+"% of values lie have a distance of at most "+str(quant)+" from the maximum") - print("\t75%% of the values lie in the interval %.2f plusminus %.2f" % find_smallest_q_confidence_area(ds, 0.75)) + print("\t75%% of the distances lie in the interval %.2f plusminus %.2f" % find_smallest_q_confidence_area(ds, 0.75)) + print("\t75%% of the flight lengths lie in the interval %.2f plusminus %.2f" % find_smallest_q_confidence_area(ns, 0.75)) print("") + + def analyze_virus_sizes(self): + print("\nI've seen the following %d virus sizes:" % len(self.data.observed_virus_sizes)) + for size, ndata in sorted(self.data.observed_virus_sizes.items(), key=lambda x:x[0]): + print("\t%4d: %7d times" % (size, ndata)) + + def analyze_remerge(self): + relevant = list(filter(lambda r : r.is_parent_child, self.data.remerging.values())) + durations = list(map(lambda r : r.end_time - r.begin_time, relevant)) + print(fit_gaussian(durations)) + waittimes = list(map(lambda r : r.begin_time - max(r.birth1, r.birth2), relevant)) + print(fit_gaussian(waittimes)) + -- cgit v1.2.3 From 5526f7ac73d02aff5c078b553e4e66a2d61e9308 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 30 Aug 2015 22:39:22 +0200 Subject: more analyzing stuff --- analyze.py | 4 +- reversing_game_mechanics/stuff.txt | 105 +++++++++++++++++++++++++++++++++++++ stats.py | 35 ++++++++++--- 3 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 reversing_game_mechanics/stuff.txt diff --git a/analyze.py b/analyze.py index a0537f7..2dc8c88 100644 --- a/analyze.py +++ b/analyze.py @@ -11,9 +11,9 @@ s = Stats.load(files[0]) for f in files[1:]: s.merge(f) -#s.analyze_speed() +s.analyze_speed() print("\n" + "-"*40 + "\n") -#s.analyze_visible_window(True) +s.analyze_visible_window(False) for i in ["split cell", "ejected mass", "virus"]: s.analyze_deviations(i) print("") diff --git a/reversing_game_mechanics/stuff.txt b/reversing_game_mechanics/stuff.txt new file mode 100644 index 0000000..29a5248 --- /dev/null +++ b/reversing_game_mechanics/stuff.txt @@ -0,0 +1,105 @@ +as of 2015-08-30 + +CELL SIZE VS SPEED + + size**0.45 * speed = 86.05616001328154 + + + + +SIZE VS VIEWPORT + + with 1 cells, depending on sum(size) + median ratio = 1.7025611175785798 + diag / size**0.33 = 608.971483054539 + + with 2 cells, depending on sum(size) + median ratio = 1.6963503649635037 + diag / size**0.33 = 585.5509541758322 + + with 3 cells, depending on sum(size) + median ratio = 1.6898326898326899 + diag / size**0.58 = 170.29929514108093 + + with 4 cells, depending on sum(size) + median ratio = 1.650784427658338 + diag / size**0.0 = 3158.567553889486 + + with 1 cells, depending on sum(mass) + median ratio = 1.7025611175785798 + diag / size**0.17 = 1270.6199859482824 + + with 2 cells, depending on sum(mass) + median ratio = 1.6972934472934473 + diag / size**0.16 = 1407.4522241811242 + + with 3 cells, depending on sum(mass) + median ratio = 1.6975546975546976 + diag / size**0.28 = 910.623966202271 + + with 4 cells, depending on sum(mass) + median ratio = 1.6625734116390818 + diag / size**0.0 = 3141.1700855829763 + + + + +EJECT/SPLIT DIRECTIONS + + split cell eject/split direction deviations: mean = 0.0009390500296252917, stddev=0.31212271930689983, ndata=621 + 75% of the splits had a deviation smaller than 0.02 rad = 1.19 deg + + ejected mass eject/split direction deviations: mean = -0.021378484138331356, stddev=0.730695490707546, ndata=1585 + 75% of the splits had a deviation smaller than 0.39 rad = 22.16 deg + + + + +EJECT/SPLIT DISTANCES + + split cell eject/split distances: mean = 378.6264099585539, stddev =214.15995855502896, ndata=1226 + split cell meann = 23.37846655791191, stddevn =17.23260859398865 + 75% of the distances lie in the interval 370.30 plusminus 218.60 + 80% of the distances lie in the interval 370.30 plusminus 262.32 + max = 1205.46 + 75% of the flight lengths lie in the interval 20.00 plusminus 9.00 + 78% of the flight lengths lie in the interval 20.00 plusminus 10.80 + + ejected mass eject/split distances: mean = 473.3307839719213, stddev =159.4625848157587, ndata=1121 + ejected mass meann = 42.015165031222125, stddevn =8.5656796143937 + 75% of the distances lie in the interval 534.64 plusminus 2.10 + 77% of the distances lie in the interval 534.64 plusminus 2.52 + max = 637.28 + 75% of the flight lengths lie in the interval 44.00 plusminus 1.00 + 79% of the flight lengths lie in the interval 44.00 plusminus 1.20 + + virus eject/split distances: mean = 396.47928995805, stddev =219.79929069475193, ndata=9 + virus meann = 42.666666666666664, stddevn =6.879922480183431 + 75% of the distances lie in the interval 510.53 plusminus 363.80 + 88% of the distances lie in the interval 510.53 plusminus 436.56 + max = 580.08 + 75% of the flight lengths lie in the interval 45.00 plusminus 10.00 + 77% of the flight lengths lie in the interval 45.00 plusminus 12.00 + + + + +VIRUS SIZES + + I've seen the following 7 virus sizes: + 100: 386018 times + 106: 124015 times + 113: 72084 times + 119: 41825 times + 125: 24954 times + 131: 373398 times + 136: 11550 times + + + + +REMERGES + + 75% of the remerge durations lie at 32.00 plusminus 30.00 frames + 75% of the remerges were started after 767.00 plusminus 20.00 frames + diff --git a/stats.py b/stats.py index 42ee0ea..d65c6d3 100644 --- a/stats.py +++ b/stats.py @@ -26,6 +26,8 @@ def quantile(values, q): return 0 def find_smallest_q_confidence_area(values, q): + """Calculates the (mid, delta) with the smallest delta, such that at least q * len(values) + lie within the interval [mid-delta, mid+delta].""" try: mid = min(values, key = lambda value : quantile(list(map(lambda x : abs(x-value), values)), q)) deviation = quantile(list(map(lambda x : abs(x-mid), values)),q) @@ -34,6 +36,14 @@ def find_smallest_q_confidence_area(values, q): except: return 0,0 +def get_delta_confidence(values, mid, delta): + #"""Calculates which fraction of the values lie within [mid-delta, mid+delta]""" + #try: + return len(list(filter(lambda v : (mid-delta <= v and v <= mid+delta), values))) / len(values) + #except: + # raise + # return 0 + def avg(values): if not isinstance(values, dict): return sum(values)/len(values) @@ -359,11 +369,17 @@ class Stats: for ncells in sorted(self.data.size_vs_visible_window.keys()): if len(self.data.size_vs_visible_window[ncells]) > 0: print("\nwith "+str(ncells)+" cells, depending on sum(size)") - self.analyze_visible_window_helper(self.data.size_vs_visible_window[ncells], verbose) + try: + self.analyze_visible_window_helper(self.data.size_vs_visible_window[ncells], verbose) + except ZeroDivisionError: + print("\toops.") for ncells in sorted(self.data.mass_vs_visible_window.keys()): if len(self.data.mass_vs_visible_window[ncells]) > 0: print("\nwith "+str(ncells)+" cells, depending on sum(mass)") - self.analyze_visible_window_helper(self.data.mass_vs_visible_window[ncells], verbose) + try: + self.analyze_visible_window_helper(self.data.mass_vs_visible_window[ncells], verbose) + except ZeroDivisionError: + print("\toops.") def analyze_deviations(self, celltype): ds = self.data.eject_deviations[celltype] @@ -412,8 +428,13 @@ class Stats: #quant = quantile(list(map(lambda v : abs(v-midpoints[maxidx]), ds)), q/100) #print("\t"+str(q)+"% of values lie have a distance of at most "+str(quant)+" from the maximum") - print("\t75%% of the distances lie in the interval %.2f plusminus %.2f" % find_smallest_q_confidence_area(ds, 0.75)) - print("\t75%% of the flight lengths lie in the interval %.2f plusminus %.2f" % find_smallest_q_confidence_area(ns, 0.75)) + mid, delta = find_smallest_q_confidence_area(ds, 0.75) + print("\t75%% of the distances lie in the interval %.2f plusminus %.2f" % (mid,delta)) + print("\t%2d%% of the distances lie in the interval %.2f plusminus %.2f" % (100*get_delta_confidence(ds, mid, delta*1.2), mid, delta*1.2) ) + print("\tmax = %.2f" % (max(ds))) + mid, delta = find_smallest_q_confidence_area(ns, 0.75) + print("\t75%% of the flight lengths lie in the interval %.2f plusminus %.2f" % (mid,delta)) + print("\t%2d%% of the flight lengths lie in the interval %.2f plusminus %.2f" % (100*get_delta_confidence(ns,mid,delta*1.2),mid,delta*1.2)) print("") def analyze_virus_sizes(self): @@ -424,7 +445,7 @@ class Stats: def analyze_remerge(self): relevant = list(filter(lambda r : r.is_parent_child, self.data.remerging.values())) durations = list(map(lambda r : r.end_time - r.begin_time, relevant)) - print(fit_gaussian(durations)) + print("75%% of the remerge durations lie at %.2f plusminus %.2f frames" % find_smallest_q_confidence_area(durations,0.75)) waittimes = list(map(lambda r : r.begin_time - max(r.birth1, r.birth2), relevant)) - print(fit_gaussian(waittimes)) - + print("75%% of the remerges were started after %.2f plusminus %.2f frames" % find_smallest_q_confidence_area(waittimes,0.75)) + -- cgit v1.2.3 From 50921e339daf8f2c4cae8ab792e97b8a35a90dbe Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 31 Aug 2015 17:52:18 +0200 Subject: virus direction stats --- game_mechanics.txt | 8 ------ gui.py | 9 ++++++ reversing_game_mechanics/game_mechanics.txt | 8 ++++++ subscriber.py | 44 ++++++++++++++++++++++++++++- 4 files changed, 60 insertions(+), 9 deletions(-) delete mode 100644 game_mechanics.txt create mode 100644 reversing_game_mechanics/game_mechanics.txt diff --git a/game_mechanics.txt b/game_mechanics.txt deleted file mode 100644 index 9c64805..0000000 --- a/game_mechanics.txt +++ /dev/null @@ -1,8 +0,0 @@ -can eject: if size >= 60 i.e. mass >= 35 -eject makes me lose 16 mass -eject distance is between (600+my.size) and (700+my.size), about 10-15 deg deviation -can eat ejected mass if mass >= 18 i.e. size >= 43 - -cell can eat us, if their size/mass(??) is at least 1.25* our size/mass - -zoom level is 369.399 * sum(own_cells.size) ** 0.431776 diff --git a/gui.py b/gui.py index 6ba6f36..2040f32 100644 --- a/gui.py +++ b/gui.py @@ -319,8 +319,12 @@ def draw_markers(): def draw_debug(): for cell in c.world.cells.values(): parent = None + shoot_vec = None + settled = None try: parent = cell.parent + shoot_vec = cell.shoot_vec + settled = cell.calmed_down except AttributeError: pass @@ -329,6 +333,11 @@ def draw_debug(): draw_circle(parent.pos,3,(255,0,0),True) + if shoot_vec != None and settled != True: + shoot_vec = 400 * shoot_vec / shoot_vec.len() + draw_line(cell.pos, cell.pos+shoot_vec, (0,255,255)) + + def draw_frame(): global screen, movement, zoom, screensize, input, bot_input, marker, marker_updated, running diff --git a/reversing_game_mechanics/game_mechanics.txt b/reversing_game_mechanics/game_mechanics.txt new file mode 100644 index 0000000..9c64805 --- /dev/null +++ b/reversing_game_mechanics/game_mechanics.txt @@ -0,0 +1,8 @@ +can eject: if size >= 60 i.e. mass >= 35 +eject makes me lose 16 mass +eject distance is between (600+my.size) and (700+my.size), about 10-15 deg deviation +can eat ejected mass if mass >= 18 i.e. size >= 43 + +cell can eat us, if their size/mass(??) is at least 1.25* our size/mass + +zoom level is 369.399 * sum(own_cells.size) ** 0.431776 diff --git a/subscriber.py b/subscriber.py index 483ae04..4327e04 100644 --- a/subscriber.py +++ b/subscriber.py @@ -82,14 +82,37 @@ class EnhancingSubscriber(DummySubscriber): self.c = None self.history = {} self.time = 0 + self.victims = {} def set_client(self,c): self.c = c + + def cleanup_victims(self): + delete = [] + + for eater in self.victims: + self.victims[eater] = list(filter(lambda v : v[1] < self.time - 100, self.victims[eater])) + if len(self.victims[eater]) == 0: + delete += [eater] + + for eater in delete: + del self.victims[eater] + def on_cell_eaten(self, eater_id, eaten_id): + if self.c.world.cells[eater_id].is_virus: + print("virus ate something!") + if eater_id not in self.victims: + self.victims[eater_id] = [] + + self.victims[eater_id] += [(self.c.world.cells[eaten_id], self.time)] + def on_world_update_post(self): self.c.world.time = self.time self.time += 1 + if self.time % 100 == 0: + self.cleanup_victims() + # create and purge poslog history, movement and movement_angle for cid in self.history: self.history[cid].stale = True @@ -183,7 +206,26 @@ 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 + try: + last_feed = self.victims[cell.parent.cid][-1][0] + if not last_feed.is_ejected_mass: + print("wtf, last virus feed was not ejected mass?!") + raise KeyError + else: + cell.shoot_vec = cell.parent.pos - last_feed.poslog[0] + cell.shoot_vec2 = last_feed.poslog[0] - last_feed.poslog[-1] + try: + pos_when_shot = last_feed.parent.poslog[len(last_feed.poslog)] + cell.shoot_vec3 = cell.parent.pos - pos_when_shot + except: + print("MOAAAHH") + cell.shoot_vec3 = None + except KeyError: + print("wtf, no last virus feed?!") + cell.shoot_vec = None + cell.shoot_vec2 = None + cell.shoot_vec3 = None + cell.calmed_down = False elif cell.is_ejected_mass: -- cgit v1.2.3 From 1b71192eca047f8d13d6570bb623627389e5acc3 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 31 Aug 2015 18:10:17 +0200 Subject: fixed weird problem, wtf before this change, the bot was always heading to (0,0), instead of heading towards the next available food. This seems to be related to world.cells being a defaultdict(Cell) (and not an ordinary dict). Also, changing the dict index `eater_id` to something nonexistent like `1`, the bug vanished as well. --- subscriber.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subscriber.py b/subscriber.py index 4327e04..ecec729 100644 --- a/subscriber.py +++ b/subscriber.py @@ -99,8 +99,9 @@ class EnhancingSubscriber(DummySubscriber): del self.victims[eater] def on_cell_eaten(self, eater_id, eaten_id): - if self.c.world.cells[eater_id].is_virus: + if eater_id in self.c.world.cells and self.c.world.cells[eater_id].is_virus: print("virus ate something!") + if eater_id not in self.victims: self.victims[eater_id] = [] -- cgit v1.2.3 From 074b6cc570cdf897a2f9974617b53267faff6a13 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 31 Aug 2015 20:07:10 +0200 Subject: virus{,2,3} logs for deviation --- stats.py | 28 ++++++++++++++++++++++++++-- strategy.py | 6 +++--- subscriber.py | 4 ++-- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/stats.py b/stats.py index d65c6d3..b263f01 100644 --- a/stats.py +++ b/stats.py @@ -108,7 +108,7 @@ class Stats: 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" : []} + self.data.eject_deviations = {"virus" : [], "virus2" : [], "virus3" : [], "split cell" : [], "ejected mass" : []} self.data.observed_virus_sizes = defaultdict(return_zero) self.data.remerging = {} @@ -173,7 +173,7 @@ class Stats: def process_frame(self): self.countdown -= 1 - if (self.countdown <= 0): + if False and (self.countdown <= 0): quick_followup = (random.random() < 0.1) if quick_followup: @@ -295,6 +295,30 @@ class Stats: self.data.eject_deviations[celltype] += [deviation] + if (celltype == 'virus'): + # FIXME so ugly + try: + shoot_angle = math.atan2(cell.shoot_vec2.y, cell.shoot_vec2.x) + + deviation = (fly_angle - shoot_angle) % (2*math.pi) + if deviation > math.pi: deviation -= 2*math.pi + print(" deviation2= "+str(deviation*180/math.pi)) + + self.data.eject_deviations['virus2'] += [deviation] + except AttributeError: + print("virus2 not available, wtf?!") + + try: + shoot_angle = math.atan2(cell.shoot_vec3.y, cell.shoot_vec3.x) + + deviation = (fly_angle - shoot_angle) % (2*math.pi) + if deviation > math.pi: deviation -= 2*math.pi + print(" deviation3= "+str(deviation*180/math.pi)) + + self.data.eject_deviations['virus3'] += [deviation] + except AttributeError: + print("virus3 not available") + else: print(celltype+" did NOT fly in a straight line, ignoring...") diff --git a/strategy.py b/strategy.py index 21a06cf..67b3da9 100644 --- a/strategy.py +++ b/strategy.py @@ -113,17 +113,17 @@ class Strategy: my_smallest = min(self.c.player.own_cells, key=lambda cell : cell.mass) my_largest = max(self.c.player.own_cells, key=lambda cell : cell.mass) - friendly_cells = list(filter(lambda c : c.name in friendly_players, self.c.world.cells.values())) + friendly_cells = list(filter(lambda c : c.is_virus or c.name in friendly_players, self.c.world.cells.values())) if friendly_cells: dist_to_friend = min(map(lambda c : (self.c.player.center-c.pos).len() - max(my_largest.size, c.size), friendly_cells)) else: dist_to_friend = float('inf') - if dist_to_friend < 20 or my_largest.mass < 60: + if dist_to_friend < 20 or my_largest.mass < 36: if self.do_approach_friends: print("not approaching friends") self.do_approach_friends = False - elif dist_to_friend > 200 and my_largest.mass > 60 + 1*16: + elif dist_to_friend > 200 and my_largest.mass > 36 + 10*16: if not self.do_approach_friends: print("approaching friends") self.do_approach_friends = True diff --git a/subscriber.py b/subscriber.py index ecec729..b89a6a9 100644 --- a/subscriber.py +++ b/subscriber.py @@ -214,9 +214,9 @@ class EnhancingSubscriber(DummySubscriber): raise KeyError else: cell.shoot_vec = cell.parent.pos - last_feed.poslog[0] - cell.shoot_vec2 = last_feed.poslog[0] - last_feed.poslog[-1] + cell.shoot_vec2 = last_feed.poslog[-1] - last_feed.poslog[0] try: - pos_when_shot = last_feed.parent.poslog[len(last_feed.poslog)] + pos_when_shot = last_feed.parent.poslog[-len(last_feed.poslog)] cell.shoot_vec3 = cell.parent.pos - pos_when_shot except: print("MOAAAHH") -- cgit v1.2.3 From 2371258d8eb6da11a7c9c5669c9f499ba44bf02a Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 31 Aug 2015 21:49:45 +0200 Subject: display how many shots a virus can take (closes #16) --- gui.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gui.py b/gui.py index 2040f32..001fc80 100644 --- a/gui.py +++ b/gui.py @@ -203,6 +203,9 @@ def generate_virus(spikes, spike_length, radius, global_coords): return points def draw_cell(cell): + font_size = 16 + virus_sizes = {100:1, 106:2, 113:3, 119:4, 125:5, 131:6, 136:7} + cx,cy = world_to_win_pt(cell.pos,c.player.center) try: mov_ang = cell.movement_angle @@ -229,6 +232,9 @@ def draw_cell(cell): gfxdraw.filled_polygon(screen, polygon2, color) gfxdraw.aapolygon(screen, polygon2, color) + + draw_text((cx, cy), "%s / 7" % virus_sizes.get(cell.size, "?"), (64,0,0), font_size*2, False, True) + draw_text((cx, cy + radius + 10), str(cell.cid), (0,0,0), font_size, False, True) else: color=(int(cell.color[0]*255), int(cell.color[1]*255), int(cell.color[2]*255)) @@ -242,8 +248,6 @@ def draw_cell(cell): gfxdraw.aacircle(screen, cx, cy, int(radius/2), (255,255,255)) gfxdraw.circle(screen, cx, cy, int(radius/2), (255,255,255)) - font_size = 16 - draw_text((cx, cy + radius + 10), cell.name, (0, 0, 0), font_size, False, True) draw_text((cx, cy + radius + 10 + font_size), str(cell.cid), (0,0,0), font_size, False, True) # surface = draw_text(cell.name, (0, 0, 0), font_size) -- cgit v1.2.3 From c13c6ca7f3d2ed069d8b0d9af4a09ea2c952d845 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 31 Aug 2015 22:42:56 +0200 Subject: --nogui flag. closes #14 --- main.py | 13 +++++++++++-- strategy.py | 20 ++++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/main.py b/main.py index d07b6b8..b9fc832 100644 --- a/main.py +++ b/main.py @@ -7,12 +7,21 @@ import sys import math import time import random -import gui +import nogui as gui # might be overridden later. import stats from subscriber import EnhancingSubscriber from interval_utils import * from strategy import * +if "--nogui" in sys.argv: + sys.argv.remove("--nogui") +else: + try: + import gui + except: + print("ERROR: could not import gui... running without gui.") + + # global vars sub = EnhancingSubscriber() c = client.Client(sub) @@ -53,7 +62,7 @@ c.player.nick=nick gui.set_client(c) # initialize strategy -strategy = Strategy(c) +strategy = Strategy(c, gui) autorespawn_counter = 60 diff --git a/strategy.py b/strategy.py index 67b3da9..900cf8f 100644 --- a/strategy.py +++ b/strategy.py @@ -1,20 +1,24 @@ import math from interval_utils import * -import gui import random +import nogui friendly_players=["Windfisch","windfisch","Cyanide","cyanide"] +\ ["Midna","Nayru","Farore","Din","Ezelo","Navi","Zelda","Tetra","Link","Ciela","Linebeck","Salia","Epona","Shiek"] +\ ["Vaati","Ganon","Ganondorf","Ghirahim","Agahnim"] class Strategy: - def __init__(self, c): + def __init__(self, c, gui=None): self.target = (0,0) self.has_target = False self.target_cell = None self.color = (0,0,0) self.c = c self.do_approach_friends = True + if gui != None: + self.gui = gui + else: + self.gui = nogui def get_my_smallest(self): return sorted(self.c.player.own_cells, key = lambda x: x.mass)[0] @@ -133,14 +137,14 @@ class Strategy: print("friend too small") friend_to_feed = None if friend_to_feed: - gui.hilight_cell(friend_to_feed, (255,255,255),(255,127,127),30) + self.gui.hilight_cell(friend_to_feed, (255,255,255),(255,127,127),30) self.target_cell = friend_to_feed self.has_target = True if self.do_approach_friends: for c in self.c.player.own_cells: - gui.hilight_cell(c, (255,255,255), (255,127,127), 20) + self.gui.hilight_cell(c, (255,255,255), (255,127,127), 20) # can this cell feed that cell? # "False" means "No, definitely not" @@ -170,7 +174,7 @@ class Strategy: good_intervals = [] for feedable in possibly_feedable_cells: - gui.hilight_cell(feedable, (255,192,127), (127,127,255)) + self.gui.hilight_cell(feedable, (255,192,127), (127,127,255)) if feedable not in friendly_cells: break @@ -181,7 +185,7 @@ class Strategy: success_rate += area / (2*10*math.pi/180) / len(list(self.c.player.own_cells)) - gui.draw_bar(((100,40),(500,24)), success_rate, thresh=.98, color=(0,0,127)) + self.gui.draw_bar(((100,40),(500,24)), success_rate, thresh=.98, color=(0,0,127)) if success_rate >= 0.98: self.c.send_shoot() @@ -237,7 +241,7 @@ class Strategy: # a bit of debugging information for i in forbidden_intervals: - gui.draw_arc(self.c.player.center, self.c.player.total_size+10, i, (255,0,255)) + self.gui.draw_arc(self.c.player.center, self.c.player.total_size+10, i, (255,0,255)) # if however there's no enemy to avoid, try to feed a friend. or chase food or jizz randomly around else: @@ -270,6 +274,6 @@ class Strategy: # more debugging - gui.draw_line(self.c.player.center, self.target, self.color) + self.gui.draw_line(self.c.player.center, self.target, self.color) return self.target -- cgit v1.2.3 From fcbc8e4ff94f7176675f0da38a9f943bb4e4f693 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 00:01:35 +0200 Subject: analyze virus2,3 --- analyze.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analyze.py b/analyze.py index 2dc8c88..c9c3ac8 100644 --- a/analyze.py +++ b/analyze.py @@ -14,7 +14,7 @@ for f in files[1:]: s.analyze_speed() print("\n" + "-"*40 + "\n") s.analyze_visible_window(False) -for i in ["split cell", "ejected mass", "virus"]: +for i in ["split cell", "ejected mass", "virus", "virus2", "virus3"]: s.analyze_deviations(i) print("") for i in ["split cell", "ejected mass", "virus"]: -- cgit v1.2.3 From aee2f231e702c5b7fa025a297c107e086838b204 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 00:01:43 +0200 Subject: FPS, problem manager --- main.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index b9fc832..79b0e54 100644 --- a/main.py +++ b/main.py @@ -12,6 +12,54 @@ import stats from subscriber import EnhancingSubscriber from interval_utils import * from strategy import * +import time + +class Clock: + def __init__(self): + self.t = time.time() + self.fps_t = time.time() + self.fps = 27 + self.cnt = 0 + self.newfps = False + + def tic(self): + t = time.time() + result = t-self.t + self.t=t + return result + + def getfps(self): + self.cnt+=1 + if time.time() > self.fps_t + 1: + self.fps_t += 1 + self.fps = self.cnt + self.cnt = 0 + self.newfps = True + else: + self.newfps = False + return self.fps + +class ProblemException(BaseException): + pass + +class ProblemManager: + def __init__(self, setup): + self.setup = setup + self.problems = {} + for t in setup: + self.problems[t] = [] + + def report(self, prob): + self.problems[prob] += [time.time()] + self.problems[prob] = list(filter(lambda t : time.time() < t + self.setup[prob][1], self.problems[prob])) + + if len(self.problems[prob]) > self.setup[prob][0]: + print("PROBLEM: "+prob) + if self.setup[prob][2]: + raise ProblemException + +probs = ProblemManager({"network lag":(100,5,True), "strategy lag":(5,2,False), "gui lag":(5,2,False), "high fps":(300,6,True), "low fps":(5,6,True)}) + if "--nogui" in sys.argv: sys.argv.remove("--nogui") @@ -31,7 +79,7 @@ stats = stats.Stats(c) try: nick = sys.argv[2] except: - nick = "test cell pls ignore" + nick = "" for i in range(1,10): # 10 connection attempts print("trying to connect, attempt "+str(i)) @@ -66,11 +114,19 @@ strategy = Strategy(c, gui) autorespawn_counter = 60 +clock = Clock() + # main loop while gui.running: c.on_message() + if clock.tic() > 1./20: + print("NETWORK LAG") + probs.report("network lag") gui.draw_frame() + if clock.tic() > 1./40: + print("GUI SLOW") + probs.report("gui lag") if len(list(c.player.own_cells)) > 0: target = strategy.process_frame() @@ -80,6 +136,10 @@ while gui.running: stats.process_frame() + if clock.tic() > 1./25.: + print("STRATEGY LAG") + probs.report("strategy lag") + gui.draw_debug() gui.update() @@ -90,6 +150,14 @@ while gui.running: else: autorespawn_counter-=1 + fps = clock.getfps() + if clock.newfps: + print("FPS: %3d" % fps) + if fps < 24: + probs.report("low fps") + if fps > 50: + probs.report("high fps") + stats.save("stats.pickle") print("bye") -- cgit v1.2.3 From 6e3feebe36a8ff9aecc13e238c3b59ddc03c4709 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 00:02:52 +0200 Subject: forgot nogui.py m( --- nogui.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 nogui.py diff --git a/nogui.py b/nogui.py new file mode 100644 index 0000000..b2989de --- /dev/null +++ b/nogui.py @@ -0,0 +1,41 @@ +running = True +bot_input = True + +def draw_bar(rect, val, thresh=None, min=0, max=1, color=(0,0,0), barcolor=None, exceedcolor=(255,0,0), threshcolor=None): + pass + +def draw_line(p1, p2, color, global_coords=True): + pass + +def draw_box(rect, color, filled=False, global_coords=True): + pass + +def draw_circle(pos, r, color, filled=False, global_coords=True): + pass + +def hilight_cell(cell, color_inner, color_outer, r=20): + pass + +def draw_polygon(polygon, color, filled=False, global_coords=True): + pass + +def draw_path(path, color, global_coords=True): + pass + +def draw_arc(pos, r, bounds, color, global_coords=True): + pass + +def draw_text(pos, text, color, font_size=16, global_coords=True, draw_centered=False): + pass + +def update(): + pass + +def set_client(cl): + pass + +def draw_debug(): + pass + +def draw_frame(): + pass -- cgit v1.2.3 From cf9460c7926be62dac8b786a586da01b8c637ad5 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 00:12:56 +0200 Subject: improvement --- main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 79b0e54..6a50ce6 100644 --- a/main.py +++ b/main.py @@ -58,7 +58,7 @@ class ProblemManager: if self.setup[prob][2]: raise ProblemException -probs = ProblemManager({"network lag":(100,5,True), "strategy lag":(5,2,False), "gui lag":(5,2,False), "high fps":(300,6,True), "low fps":(5,6,True)}) +probs = ProblemManager({"network lag":(100,5,True), "strategy lag":(5,2,False), "gui lag":(5,2,False), "high fps":(5,6,True), "low fps":(5,6,True)}) if "--nogui" in sys.argv: @@ -155,8 +155,8 @@ while gui.running: print("FPS: %3d" % fps) if fps < 24: probs.report("low fps") - if fps > 50: - probs.report("high fps") + if fps > 50: + probs.report("high fps") stats.save("stats.pickle") -- cgit v1.2.3 From 8391000d2a03baf02cd4b3f5c46d9471e3be1127 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 00:17:34 +0200 Subject: exit if persistent problems occur. closes #21 --- main.py | 85 ++++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/main.py b/main.py index 6a50ce6..ab92ce3 100644 --- a/main.py +++ b/main.py @@ -116,47 +116,50 @@ autorespawn_counter = 60 clock = Clock() -# main loop -while gui.running: - c.on_message() - if clock.tic() > 1./20: - print("NETWORK LAG") - probs.report("network lag") - - gui.draw_frame() - if clock.tic() > 1./40: - print("GUI SLOW") - probs.report("gui lag") - - if len(list(c.player.own_cells)) > 0: - target = strategy.process_frame() - - if gui.bot_input: - c.send_target(target[0], target[1]) - - stats.process_frame() - - if clock.tic() > 1./25.: - print("STRATEGY LAG") - probs.report("strategy lag") - - gui.draw_debug() - gui.update() - - if not c.player.is_alive: - if autorespawn_counter == 0: - c.send_respawn() - autorespawn_counter = 60 - else: - autorespawn_counter-=1 - - fps = clock.getfps() - if clock.newfps: - print("FPS: %3d" % fps) - if fps < 24: - probs.report("low fps") - if fps > 50: - probs.report("high fps") +try: + # main loop + while gui.running: + c.on_message() + if clock.tic() > 1./20: + print("NETWORK LAG") + probs.report("network lag") + + gui.draw_frame() + if clock.tic() > 1./40: + print("GUI SLOW") + probs.report("gui lag") + + if len(list(c.player.own_cells)) > 0: + target = strategy.process_frame() + + if gui.bot_input: + c.send_target(target[0], target[1]) + + stats.process_frame() + + if clock.tic() > 1./25.: + print("STRATEGY LAG") + probs.report("strategy lag") + + gui.draw_debug() + gui.update() + + if not c.player.is_alive: + if autorespawn_counter == 0: + c.send_respawn() + autorespawn_counter = 60 + else: + autorespawn_counter-=1 + + fps = clock.getfps() + if clock.newfps: + print("FPS: %3d" % fps) + if fps < 24: + probs.report("low fps") + if fps > 50: + probs.report("high fps") +except ProblemException: + print("Exiting due to a problem such as low/high fps, network lags etc") stats.save("stats.pickle") -- cgit v1.2.3 From 4251e85c172f57c39bdfa244e945578eb450926d Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 00:40:27 +0200 Subject: game mechanics. closes #13 --- reversing_game_mechanics/game_mechanics.txt | 56 ++++++++++++++++++++++++++--- reversing_game_mechanics/stuff.txt | 14 +++++++- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/reversing_game_mechanics/game_mechanics.txt b/reversing_game_mechanics/game_mechanics.txt index 9c64805..2488481 100644 --- a/reversing_game_mechanics/game_mechanics.txt +++ b/reversing_game_mechanics/game_mechanics.txt @@ -1,8 +1,54 @@ -can eject: if size >= 60 i.e. mass >= 35 -eject makes me lose 16 mass -eject distance is between (600+my.size) and (700+my.size), about 10-15 deg deviation -can eat ejected mass if mass >= 18 i.e. size >= 43 +Created 2015-09-01, with data between 0 and 2 weeks old. -cell can eat us, if their size/mass(??) is at least 1.25* our size/mass +Units used: + distances, sizes are measured in raw agar.io coordinates. + times are measured in frames. The game ran at 27-28 FPS at the time + where this document was created + speeds are measured in distance / number of frames + + + +cellspeed = 86.05 / cellsize**0.45 zoom level is 369.399 * sum(own_cells.size) ** 0.431776 + +ejecting mass: + prerequisite: size >= 60, i.e. mass >= 35 + you will lose 16 mass, but only gain 12 mass if you eat the blob + one can eat ejected mass if mass >= 18 i.e. size >= 43 + + 75% of the ejects had a deviation smaller than 0.39 rad = 22.16 deg + from the original moving direction of the shooting cell + + they fly 44-45px, starting from shooting cell's border. + +splitting: + 75% of the splits had a deviation smaller than 0.02 rad = 1.19 deg + from the original moving direction of the parent + + flight distance: unknown, somewhere between 100 - 650, max = 1205 + + re-union will usually become possible somewhere after 745 - 790 frames + this means that your cells are possible to glide into each + other. depending on your movement pattern they will actually + merge sooner or later. + +feeding viruses: + 75% of the splits had a deviation smaller than 0.00 rad = 0.11 deg + from the ejected mass movement vector. + + maximum distance is 580 from the midpoint of the parent virus. + not sure about the minimum (too few data), but probably also 580? + + Viruses can have the following sizes: + 100, 106, 113, 119, 125, 131, 136. + Sometimes 141 is also observed, but those viruses will split + almost instantly (bug in the server software?) + i.e., feed a virus with size 100 6 times to maximum size, and one more + time to make it duplicate. + +eating: + a cell can eat us, if their size/mass(??) is at least 1.25* our size/mass + a cell eats another, if the smaller one's midpoint is within the + larger one's circle (with radius = size) + diff --git a/reversing_game_mechanics/stuff.txt b/reversing_game_mechanics/stuff.txt index 29a5248..fbbddc4 100644 --- a/reversing_game_mechanics/stuff.txt +++ b/reversing_game_mechanics/stuff.txt @@ -52,6 +52,18 @@ EJECT/SPLIT DIRECTIONS ejected mass eject/split direction deviations: mean = -0.021378484138331356, stddev=0.730695490707546, ndata=1585 75% of the splits had a deviation smaller than 0.39 rad = 22.16 deg + virus eject/split direction deviations: mean = -0.16497762078310707, stddev=0.07294211158929148, ndata=5 + 75% of the splits had a deviation smaller than 0.25 rad = 14.41 deg + (wrt "emitted mass begin -- parent virus") + + virus2 eject/split direction deviations: mean = -0.001211356391619578, stddev=0.0038334565337591105, ndata=5 + 75% of the splits had a deviation smaller than 0.00 rad = 0.11 deg + (wrt "emitted mass flight direction") + + virus3 eject/split direction deviations: mean = -0.13739240722341658, stddev=0.056773374975376475, ndata=5 + 75% of the splits had a deviation smaller than 0.21 rad = 11.82 deg + (wrt "emitter of the mass -- parent virus") + @@ -77,7 +89,7 @@ EJECT/SPLIT DISTANCES virus meann = 42.666666666666664, stddevn =6.879922480183431 75% of the distances lie in the interval 510.53 plusminus 363.80 88% of the distances lie in the interval 510.53 plusminus 436.56 - max = 580.08 + max = 580.08 (ndata = 13) 75% of the flight lengths lie in the interval 45.00 plusminus 10.00 77% of the flight lengths lie in the interval 45.00 plusminus 12.00 -- cgit v1.2.3 From 738d057c6da4aaca7516158db55f3553a03cf189 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 18:14:37 +0200 Subject: better "can i safely feed" estimation --- gui.py | 4 ++-- mechanics.py | 1 + strategy.py | 9 +++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/gui.py b/gui.py index 001fc80..2a8460c 100644 --- a/gui.py +++ b/gui.py @@ -209,8 +209,8 @@ def draw_cell(cell): cx,cy = world_to_win_pt(cell.pos,c.player.center) try: mov_ang = cell.movement_angle - p2 = cell.pos + Vec( math.cos(mov_ang + 26*math.pi/180), math.sin(mov_ang + 26*math.pi/180) ) * (cell.size+700) - p3 = cell.pos + Vec( math.cos(mov_ang - 26*math.pi/180), math.sin(mov_ang - 26*math.pi/180) ) * (cell.size+700) + p2 = cell.pos + Vec( math.cos(mov_ang + mechanics.eject_delta*math.pi/180), math.sin(mov_ang + mechanics.eject_delta*math.pi/180) ) * (cell.size+700) + p3 = cell.pos + Vec( math.cos(mov_ang - mechanics.eject_delta*math.pi/180), math.sin(mov_ang - mechanics.eject_delta*math.pi/180) ) * (cell.size+700) cx2,cy2 = world_to_win_pt(p2,c.player.center) cx3,cy3 = world_to_win_pt(p3,c.player.center) diff --git a/mechanics.py b/mechanics.py index 1f9d5cc..5f2254b 100644 --- a/mechanics.py +++ b/mechanics.py @@ -4,3 +4,4 @@ def speed(size): def viewport_diag(sizesum): return 370 * max(sizesum,70)**0.431776 +eject_delta = 22 # how many degrees do ejects deviate from the original direction (maximum) diff --git a/strategy.py b/strategy.py index 900cf8f..bbbe07d 100644 --- a/strategy.py +++ b/strategy.py @@ -2,6 +2,7 @@ import math from interval_utils import * import random import nogui +import mechanics friendly_players=["Windfisch","windfisch","Cyanide","cyanide"] +\ ["Midna","Nayru","Farore","Din","Ezelo","Navi","Zelda","Tetra","Link","Ciela","Linebeck","Salia","Epona","Shiek"] +\ @@ -181,12 +182,12 @@ class Strategy: good_intervals += canonicalize_angle_interval( interval_occupied_by_cell(my_cell.pos, feedable) ) good_intervals = merge_intervals(good_intervals) - area = interval_area( intersection(good_intervals, canonicalize_angle_interval((my_cell.movement_angle - 10*math.pi/180, my_cell.movement_angle + 10*math.pi/180))) ) - success_rate += area / (2*10*math.pi/180) / len(list(self.c.player.own_cells)) + area = interval_area( intersection(good_intervals, canonicalize_angle_interval((my_cell.movement_angle - mechanics.eject_delta*math.pi/180, my_cell.movement_angle + mechanics.eject_delta*math.pi/180))) ) + success_rate += area / (2*mechanics.eject_delta*math.pi/180) / len(list(self.c.player.own_cells)) - self.gui.draw_bar(((100,40),(500,24)), success_rate, thresh=.98, color=(0,0,127)) - if success_rate >= 0.98: + self.gui.draw_bar(((100,40),(500,24)), success_rate, thresh=.80, color=(0,0,127)) + if success_rate >= 0.80: self.c.send_shoot() -- cgit v1.2.3 From e06a42f55444eba9bac38103dbc82425d282a310 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 19:15:40 +0200 Subject: readjust runaway scores. partially implements #17 --- strategy.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/strategy.py b/strategy.py index bbbe07d..eeacc4f 100644 --- a/strategy.py +++ b/strategy.py @@ -192,13 +192,38 @@ class Strategy: - # enemy/virus avoidance + # enemy/virus/friend-we-would-kill avoidance forbidden_intervals = [] for cell in self.c.world.cells.values(): relpos = ((cell.pos[0]-self.c.player.center[0]),(cell.pos[1]-self.c.player.center[1])) dist = math.sqrt(relpos[0]**2+relpos[1]**2) - if ( (not cell.is_virus and dist < ((500+2*cell.size) if cell.mass > 1.25*my_smallest.mass*2 else (300+cell.size)) and cell.mass > 1.25 * my_smallest.mass) or (cell.is_virus and dist < my_largest.mass and cell.mass < my_largest.mass) ) and not (cell in friendly_cells) or (cell in friendly_cells) and dist < cell.size+10: + # find out the allowed minimum distance + allowed_dist = None + + if cell.is_virus: + if cell.mass < my_largest.mass: + allowed_dist = cell.size+2 + else: + allowed_dist = "don't care" + elif cell in friendly_cells: + if 1.25 * my_largest.mass > cell.mass: # we're dangerous to our friends + allowed_dist = my_largest.size + 40 + elif (cell not in self.c.player.own_cells and not cell.is_virus and not cell.is_ejected_mass and not cell.is_food) and cell.mass + 20 > 1.25 * my_smallest.mass: # our enemy is, or will be dangerous to us + if (cell.mass + 20) / 2 < 1.25 * my_smallest.mass: + # they can't splitkill us (soon) + allowed_dist = cell.size + 75 + elif cell.mass / 15. < self.c.player.total_mass: + # they can and they will splitkill us + allowed_dist = 650 + cell.size + else: + # we're too small, not worth a splitkill. they have absolutely no + # chance to chase us + allowed_dist = cell.size + 10 + else: + allowed_dist = "don't care" + + if allowed_dist != "don't care" and dist < allowed_dist: try: angle = math.atan2(relpos[1],relpos[0]) corridor_halfwidth = math.asin(min(1, cell.size / dist)) @@ -206,6 +231,7 @@ class Strategy: runaway = True except: print("TODO FIXME: need to handle enemy cell which is in our centerpoint!") + print("dist=%.2f, allowed_dist=%.2f" % (dist, allowed_dist)) # wall avoidance if self.c.player.center[0] < self.c.world.top_left[1]+(self.c.player.total_size*2): -- cgit v1.2.3 From 7c1180a7b58e7b8c17c8dab297058d0c001386c6 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 1 Sep 2015 20:40:10 +0200 Subject: try to chase less --- mechanics.py | 12 ++++++++++-- strategy.py | 9 ++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/mechanics.py b/mechanics.py index 5f2254b..3aaa405 100644 --- a/mechanics.py +++ b/mechanics.py @@ -1,5 +1,13 @@ -def speed(size): - return 86 / (size**0.45) +from agarnet.agarnet.world import Cell + +def speed(size_or_cell): + if isinstance(size_or_cell, Cell): + if size_or_cell.is_virus or size_or_cell.is_ejected_mass or size_or_cell.is_food: + return 0 + else: + return speed(size_or_cell.size) + else: + return 86 / (size_or_cell**0.45) def viewport_diag(sizesum): return 370 * max(sizesum,70)**0.431776 diff --git a/strategy.py b/strategy.py index eeacc4f..3d5721a 100644 --- a/strategy.py +++ b/strategy.py @@ -53,9 +53,12 @@ class Strategy: def nonsplitkiller(self, cell): return not cell.is_virus and not cell.is_food and 1.20*self.get_my_smallest().mass < cell.mass and cell.mass < 1.25*2*self.get_my_smallest().mass - def quality(self, cell): + def quality(self, cell, myspeed): dd_sq = max((cell.pos[0]-self.c.player.center[0])**2 + (cell.pos[1]-self.c.player.center[1])**2,0.001) - sigma = 500 + sigma = 500 * max(cell.mass,1) # TODO FIXME don't try to eat running away cells + if mechanics.speed(cell) - myspeed >= 0: + sigma = sigma / 3 / math.exp((mechanics.speed(cell)-myspeed)/10) + dist_score = -math.exp(-dd_sq/(2*sigma**2)) rivals = filter(lambda r : self.rival(r,cell), self.c.world.cells.values()) @@ -283,7 +286,7 @@ class Strategy: if not self.has_target: food = list(filter(self.edible, self.c.world.cells.values())) - food = sorted(food, key = self.quality) + food = sorted(food, key = lambda c : self.quality(c, mechanics.speed(my_largest))) if len(food) > 0: self.target = (food[0].pos[0], food[0].pos[1]) -- cgit v1.2.3