commit 9fd025d3a7ac554ea3ccb2c1d87ee046a39766bf Author: wjsjwr Date: Sun Mar 11 17:16:26 2018 +0800 initital commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce5e416 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +graph +wos-data-new +wos-data-casual +*.svg +__pycache__ \ No newline at end of file diff --git a/.vscode/database.json b/.vscode/database.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.vscode/database.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e69de29 diff --git a/actions_after_defect.py b/actions_after_defect.py new file mode 100644 index 0000000..bfa70b2 --- /dev/null +++ b/actions_after_defect.py @@ -0,0 +1,49 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches + +matches = Matches('wos-data-new') + +labels = ['link', 'unlink'] +percents = [0.0, 0.0] + +for m in matches.data: + info = m.query('game', 'created').select('info').first()['info'] + conf = json.loads(info['config']) + game_end_at = int(info['game_end_at']) + + for row in m.query('action', 'done').where(lambda x: x['act_a'] == 'D' or x['act_b'] == 'D').raw_data: + if row['rno'] == game_end_at: + print(row) + continue + if row['act_a'] == 'D': + a = row['a'] + b = row['b'] + n = m.query('action', 'done').where(lambda y: ((y['a'] == a and y['b'] == b) or (y['a'] == b and y['b'] == a)) and y['rno'] == row['rno'] + 1).raw_data + if n: + percents[0] += 1 + else: + percents[1] += 1 + if row['act_b'] == 'D': + a = row['a'] + b = row['b'] + n = m.query('action', 'done').where(lambda y: ((y['a'] == a and y['b'] == b) or (y['a'] == b and y['b'] == a)) and y['rno'] == row['rno'] + 1).raw_data + if n: + percents[0] += 1 + else: + percents[1] += 1 + +_all = sum(percents) / 100 +percents[0] /= _all +percents[1] /= _all + +plt.figure() +patches, texts, autotexts = plt.pie(percents, labels=labels, autopct='%1.1f%%', startangle=90) + +for t in texts: + t.set_size('xx-large') + +plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. +plt.show() +# plt.savefig('graph/actions_after_defect.png') \ No newline at end of file diff --git a/after_d_link_tr.py b/after_d_link_tr.py new file mode 100644 index 0000000..5808f44 --- /dev/null +++ b/after_d_link_tr.py @@ -0,0 +1,61 @@ +import json +from matplotlib import pyplot as plt +from matplotlib.ticker import PercentFormatter +from island.match import Match +from island.matches import Matches + +matches = Matches('wos-data-new') + +lx=[] +ly=[] + +h = [] + +for m in matches.data: + info = m.query('game', 'created').select('info').first()['info'] + conf = json.loads(info['config']) + game_end_at = int(info['game_end_at']) + + for row in m.query('action', 'done').where(lambda x: x['act_a'] == 'D' or x['act_b'] == 'D').raw_data: + if row['rno'] == game_end_at: + print(row) + continue + if row['act_a'] == 'D': + a = row['a'] + b = row['b'] + n = m.query('action', 'done').where(lambda y: ((y['a'] == a and y['b'] == b) or (y['a'] == b and y['b'] == a)) and y['rno'] == row['rno'] + 1).raw_data + if n: + h.append(n[0]['tr']) + if n[0]['tr'] in lx: + ly[lx.index(n[0]['tr'])] += 1 + else: + lx.append(n[0]['tr']) + ly.append(1) + if row['act_b'] == 'D': + a = row['a'] + b = row['b'] + n = m.query('action', 'done').where(lambda y: ((y['a'] == a and y['b'] == b) or (y['a'] == b and y['b'] == a)) and y['rno'] == row['rno'] + 1).raw_data + if n: + h.append(n[0]['tr']) + if n[0]['tr'] in lx: + ly[lx.index(n[0]['tr'])] += 1 + else: + lx.append(n[0]['tr']) + ly.append(1) + +al = sum(ly) + +ly = map(lambda y: float(y) / float(al), ly) + +_bin = [x * 120 for x in range(13)] + +fig = plt.figure() +n,b,p = plt.hist(h, _bin, normed=True, ec='k') +ax = fig.gca() +ax.yaxis.set_major_formatter(PercentFormatter(xmax=sum(n))) +print(n) +print(b) +print(p) +print(sum(n)) +# plt.show() +plt.savefig('graph/after_d_link_tr.png') \ No newline at end of file diff --git a/calc_winner_pid.py b/calc_winner_pid.py new file mode 100644 index 0000000..c2e4a4d --- /dev/null +++ b/calc_winner_pid.py @@ -0,0 +1,35 @@ +import json +from pathlib import Path +from island.match import Match + + + +result = {} + +for file in Path('wos-data-new').iterdir(): + p = Path(file) + if p.suffix == '.json': + name = p.stem + m = Match.read_from_json(str(file)) + info = m.query('game', 'created').select('info').first()['info'] + conf = json.loads(info['config']) + game_end_at = int(info['game_end_at']) + players = [] + foods = {} + for p in m.query('player', 'join').select('pid').raw_data: + foods[p['pid']] = conf['start_resource'] + + for i in range(1, game_end_at+1): + for a in m.query('action', 'done').where(lambda x: x['rno'] == i).raw_data: + foods[a['a']] += conf['payoffs']["%s%s"%(a['act_a'], a['act_b'])][0] * a['tr'] / 1440.0 + foods[a['b']] += conf['payoffs']["%s%s"%(a['act_a'], a['act_b'])][1] * a['tr'] / 1440.0 + for j in foods.keys(): + foods[j] -= conf['rounds']['consumption'] + + for j in foods.keys(): + if foods[j] > 0: + players.append(j) + + result[name] = players + +print(json.dumps(result)) \ No newline at end of file diff --git a/coopr_per_match.py b/coopr_per_match.py new file mode 100644 index 0000000..422dd80 --- /dev/null +++ b/coopr_per_match.py @@ -0,0 +1,55 @@ +import json +from matplotlib import pyplot as plt +import scipy as sp +from island.match import Match +from island.matches import Matches + +def error(f,x,y): + return sp.sum((f(x)-y)**2) + +matches = Matches('wos-data-new') +max_round = 17 + +coopr = [] +data = {} +x = [] +_x = [] + +survivals = {} +with open('winner.json','r') as f: + survivals = json.load(f) + +for j in range(len(matches.data)): + coop = 0 + rows = matches.data[j].query('action', 'done').raw_data + info = matches.data[j].query('game', 'created').select('info').raw_data[0]['info'] + ns = int(info['next_start']) + for row in rows: + if row['act_a'] == 'C' and row['act_b'] == 'C': + coop += 1 + + if rows: + data[ns] = float(coop) / len(rows) + x.append(ns) + +x = sorted(x) +for i in range(len(x)): + _x.append(i) + coopr.append(data[x[i]]) + +fig = plt.figure() +plt.scatter(_x, coopr) +ax = fig.gca() +plt.ylim(0,1) +fp1,residuals,rank,sv,rcond = sp.polyfit(_x, coopr, 1, full=True) +print("残差:",residuals) +print('Model parameter:',fp1) +f1 = sp.poly1d(fp1) +print(error(f1, _x, coopr)) +fx = sp.linspace(0,_x[-1],1000) + +plt.plot(fx,f1(fx),linewidth=1,color='red') + + +# plt.show() +plt.savefig('graph/co_per_game.png') \ No newline at end of file diff --git a/coopr_per_round.py b/coopr_per_round.py new file mode 100644 index 0000000..0b6f1aa --- /dev/null +++ b/coopr_per_round.py @@ -0,0 +1,45 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches + +matches = Matches('wos-data-new') +max_round = 17 + +coopr = [] +yerr_min = [] +yerr_max = [] +x = [] +bx = [] + +survivals = {} +with open('winner.json','r') as f: + survivals = json.load(f) + +for i in range(max_round): + co = [] + for j in range(len(matches.data)): + coop = 0 + rows = matches.data[j].query('action', 'done').where(lambda x: x['rno']==i+1).raw_data + for row in rows: + if row['act_a'] == 'C' and row['act_b'] == 'C': + coop += 1 + + if rows: + co.append(float(coop) / float(len(rows))) + + bx.append(co) + + if co: + coopr.append(sum(co) / len(co)) + + yerr_min.append(coopr[-1] - min(co)) + yerr_max.append(max(co) - coopr[-1]) + print("%f, %f, %f"%(yerr_min[-1], yerr_max[-1], coopr[-1])) + x.append(i+1) + +plt.figure() +# plt.errorbar(x, coopr, yerr=[yerr_min, yerr_max], fmt='o', capsize=4) +plt.boxplot(bx, showmeans=True, meanline=True) +# plt.show() +plt.savefig('graph/co_per_round.png') \ No newline at end of file diff --git a/defector_has_neighbor.py b/defector_has_neighbor.py new file mode 100644 index 0000000..97d0ab1 --- /dev/null +++ b/defector_has_neighbor.py @@ -0,0 +1,46 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches + +matches = Matches('wos-data-new') + +labels = ['has neighbor', 'no neighbor'] +percents = [0.0, 0.0] + +for m in matches.data: + info = m.query('game', 'created').select('info').first()['info'] + conf = json.loads(info['config']) + game_end_at = int(info['game_end_at']) + + for row in m.query('action', 'done').where(lambda x: x['act_a'] == 'D' or x['act_b'] == 'D').raw_data: + if row['rno'] == game_end_at: + print(row) + continue + if row['act_a'] == 'D': + a = row['a'] + b = row['b'] + o = m.query('action', 'done').where(lambda y: (y['b'] == a or y['a'] == a) and y['rno'] == row['rno'] + 1).raw_data + if o: + percents[0] += 1 + else: + percents[1] += 1 + if row['act_b'] == 'D': + a = row['a'] + b = row['b'] + o = m.query('action', 'done').where(lambda y: (y['b'] == b or y['a'] == b) and y['rno'] == row['rno'] + 1).raw_data + if o: + percents[0] += 1 + else: + percents[1] += 1 + + +_all = sum(percents) / 100 +percents[0] /= _all +percents[1] /= _all + +plt.figure() +plt.pie(percents, labels=labels, autopct='%1.1f%%', startangle=90) +plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. +plt.show() +# plt.savefig('graph/unlink_has_neighbor.png') \ No newline at end of file diff --git a/draw_game_history.py b/draw_game_history.py new file mode 100644 index 0000000..620a0b6 --- /dev/null +++ b/draw_game_history.py @@ -0,0 +1,285 @@ +import json +import math + +from cairo import Context, LineCap, LineJoin, PSSurface, SVGSurface +# from scipy.integrate import quad + +from island.match import Match + + +class Point: + def __init__(self, x, y): + self.x = x + self.y = y + + def move_to(self, newx, newy): + self.x = newx + self.y = newy + + def rel_move_to(self, offx, offy): + self.x += offx + self.y += offy + + def new_rel_point(self, offx, offy): + return Point(self.x + offx, self.y + offy) + +class Color: + def __init__(self, r = 0, g = 0, b = 0, a = 0): + self.r = r + self.g = g + self.b = b + self.a = a + + def shade(self, percentage): + return Color(self.r, self.g, self.b, 0.8 * percentage + 0.2) + +def set_color(ctx, color): + """ + :param ctx: context + :param color: the Color + """ + ctx.set_source_rgba(color.r, color.g, color.b, color.a) + +def draw_alive_face(ctx, pt, r, w): + """ + :param ctx: context + :param pt: the center point + :param r: radius + :param w: line width + """ + ctx.new_path() + ctx.set_source_rgba(1, 1, 1, 1) + ctx.set_line_width(w) + ctx.arc(pt.x, pt.y, r, 0, 2*math.pi) + ctx.fill() + ctx.set_source_rgba(0, 0, 0, 1) + ctx.arc(pt.x, pt.y, r, 0, 2*math.pi) + ctx.stroke() + ctx.arc(pt.x - r / SQRT2 / 2, pt.y - r / SQRT2 / 2, r / 10, 0, 2 * math.pi) + ctx.fill() + ctx.arc(pt.x + r / SQRT2 / 2, pt.y - r / SQRT2 / 2, r / 10, 0, 2 * math.pi) + ctx.fill() + ctx.set_line_cap(LineCap.ROUND) + ctx.arc(pt.x, pt.y, r * GOLDEN_SECTION, math.pi / 4, math.pi / 4 * 3) + ctx.stroke() + + +def draw_dead_face(ctx, pt, r, w): + """ + :param ctx: context + :param pt: the center point + :param r: radius + :param w: line width + """ + ctx.set_line_cap(LineCap.ROUND) + ctx.set_line_join(LineJoin.ROUND) + + ctx.new_path() + ctx.set_source_rgba(1, 1, 1, 1) + ctx.set_line_width(w) + ctx.arc(pt.x, pt.y, r, 0, 2*math.pi) + ctx.fill() + ctx.set_source_rgba(0.5, 0.5, 0.5, 1) + ctx.arc(pt.x, pt.y, r, 0, 2*math.pi) + ctx.stroke() + + offset = r / 6 * SQRT3 / 2 + ctx.move_to(pt.x - r / SQRT2 / 2 + offset, pt.y - r / SQRT2 / 2 + r / 6) + ctx.rel_line_to(- r / 6 * SQRT3, - r / 6) + ctx.move_to(pt.x - r / SQRT2 / 2 + offset, pt.y - r / SQRT2 / 2 + r / 6) + ctx.rel_line_to(- r / 6 * SQRT3, r / 6) + ctx.move_to(pt.x + r / SQRT2 / 2 - offset, pt.y - r / SQRT2 / 2 + r / 6) + ctx.rel_line_to(r / 6 * SQRT3, - r / 6) + ctx.move_to(pt.x + r / SQRT2 / 2 - offset, pt.y - r / SQRT2 / 2 + r / 6) + ctx.rel_line_to(r / 6 * SQRT3, r / 6) + ctx.stroke() + + a = r * GOLDEN_SECTION + ctx.move_to(pt.x - a / SQRT2, pt.y + a / SQRT2) + step = a / (4 * SQRT2) + for _ in range(4): + ctx.rel_line_to(step, -step) + ctx.rel_line_to(step, step) + ctx.stroke() + +def bezier_diff(x, cax, cbx, ccx, cay, cby, ccy): + return math.sqrt((cax + cbx * x + ccx * (x ** 2)) ** 2 + (cay + cby * x + ccy * (x ** 2)) ** 2) + +def calc_bezier_diff_angle(p0, p1, p2, p3, al): + """ + f(x) = a - 3ax + 3ax^2 - ax^3 + 3bx - 6bx^2 + 3bx^3 + 3cx^2 - 3cx^3 + dx^3 + f'(x) = (-3a+3b) + 2(3a - 6b +3c)x + 3(-a+3b-3c+d)x^2 + """ + # cax = -3 * p0.x + 3 * p1.x + # cbx = 6 * p0.x - 12 * p1.x + 6 * p2.x + # ccx = -3 * p0.x + 9 * p1.x - 9 * p2.x + 3 * p3.x + # cay = -3 * p0.y + 3 * p1.y + # cby = 6 * p0.y - 12 * p1.y + 6 * p2.y + # ccy = -3 * p0.y + 9 * p1.y - 9 * p2.y + 3 * p3.y + + # s = quad(bezier_diff, 0, 1, args=(cax, cbx, ccx, cay, cby, ccy)) + # t = 1 - al / s[0] * 1.1 + # bx = p0.x * (1-t) ** 3 + 3 * p1.x * t * (1-t) ** 2 + 3 * p2.x * t ** 2 * (1-t) + p3.x * t ** 3 + # by = p0.y * (1-t) ** 3 + 3 * p1.y * t * (1-t) ** 2 + 3 * p2.y * t ** 2 * (1-t) + p3.y * t ** 3 + # a = math.asin((by - p3.y) / math.sqrt((bx - p3.x) ** 2 + (by - p3.y) ** 2)) + # if bx < p3.x: + # a = math.pi - a + a = math.pi * 5 / 4 if p0.x < p3.x else math.pi / 4 + return a - math.pi / 30 + +def draw_action_arrow(ctx, cf, ct, w, al, r, c): + """ + :param ctx: context + :param cf: from the center point + :param ct: to the center point + :param w: line width + :param al: arrow length + :param r: radius + :param c: Color + """ + ctx.set_source_rgba(c.r, c.g, c.b, c.a) + ctx.set_line_width(w) + ctx.set_line_cap(LineCap.ROUND) + ltr = 1 if cf.x < ct.x else -1 + af = Point(cf.x + ltr * r / SQRT2, cf.y - ltr * r / SQRT2) + at = Point(ct.x - ltr * r / SQRT2, ct.y - ltr * r / SQRT2) + ctx.move_to(af.x, af.y) + extend = (ltr * (ct.x - cf.x)) ** 0.7 + p1 = Point(af.x + ltr * extend / SQRT2, af.y - ltr * extend / SQRT2) + p2 = Point(at.x - ltr * extend / SQRT2, at.y - ltr * extend / SQRT2) + ctx.curve_to(p1.x, p1.y, p2.x, p2.y, at.x, at.y) + a = calc_bezier_diff_angle(af, p1, p2, at, al) + ctx.move_to(at.x, at.y) + ctx.line_to(at.x + al * math.cos(a - math.pi / 12), at.y + al * math.sin(a - math.pi / 12)) + ctx.move_to(at.x, at.y) + ctx.line_to(at.x + al * math.cos(a + math.pi / 12), at.y + al * math.sin(a + math.pi / 12)) + ctx.stroke() + +def draw_food_bar(ctx, refp, food, foodi, w, h): + """ + :param ctx: context + :param refp: reference point, left bottom + :param food: food + :param foodi: initial food + :param w: bar width + :param h: bar height + """ + ctx.set_line_width(w / 10) + ctx.set_line_cap(LineCap.SQUARE) + ctx.set_line_join(LineJoin.MITER) + if food > 0: + foodh = food / foodi * h + ctx.rectangle(refp.x, refp.y - foodh, w, foodh) + set_color(ctx, TAMAMOROKOSHI) + ctx.fill() + ctx.rectangle(refp.x, refp.y - h, w, h) + ctx.set_source_rgba(0, 0, 0, 1) + ctx.stroke() + + +def draw_faces(ctx, p, f, r, lw): + """ + :param ctx: context + :param p: positions + :param f: foods + :param r: radius + :param lw: line width + """ + for k in p.keys(): + if f[k] > 0: + draw_alive_face(context, p[k], r, lw) + else: + draw_dead_face(context, p[k], r, lw) + + draw_food_bar(ctx, p[k].new_rel_point(r / SQRT2 + 20, r / SQRT2), f[k], 5, 10, r * SQRT2) + draw_text(ctx, str(k), Point(p[k].x, p[k].y - r - 15), Point(p[k].x, p[k].y - r - 5), CENTER_ALIGNED|MIDDLE_ALIGNED, 12) + +def draw_text(ctx, text, tl, rb, align, font_size=None, font_face=None, font_matrix=None, font_options=None): + """ + draw text + :param ctx: context + :param text: the text + :param tl: the top-left reference point + :param rb: the right-bottom reference point + :param align: alignment + :param font_size: float font size + :param font_face: font face + :param font_matrix: font matrix + :param font_options: font options + """ + if font_size is not None: + ctx.set_font_size(font_size) + if font_face is not None: + ctx.set_font_face(font_face) + if font_matrix is not None: + ctx.set_font_matrix(font_matrix) + if font_options is not None: + ctx.set_font_options(font_options) + + te = ctx.text_extents(text) + ha = align & 0b00001111 + if ha == CENTER_ALIGNED: + x = (rb.x + tl.x - te.width) / 2 - te.x_bearing / 2 + elif ha == RIGHT_ALIGNED: + x = rb.x - te.width + else:# ha == LEFT_ALIGNED + x = tl.x - te.x_bearing + va = align & 0b11110000 + if va == MIDDLE_ALIGNED: + y = (rb.y + tl.y + te.height) / 2 - (te.height + te.y_bearing) / 2 + elif va == BOTTOM_ALIGNED: + y = rb.y + else: #va == TOP_ALIGNED: + y = tl.y + te.height - (te.height + te.y_bearing) + ctx.move_to(x, y) + ctx.show_text(text) + +LEFT_ALIGNED = 0b00000001 +CENTER_ALIGNED = 0b00000010 +RIGHT_ALIGNED = 0b00000100 +TOP_ALIGNED = 0b00010000 +MIDDLE_ALIGNED = 0b00100000 +BOTTOM_ALIGNED = 0b01000000 + +GOLDEN_SECTION = 0.6180339887 +SQRT2 = 1.4142135623 +SQRT3 = 1.7320508076 + +FACE_WIDTH = 100 +FACE_INTERVAL = 50 +ROUND_HEIGHT = 300 +LINEWIDTH = 4 + +TAMAMOROKOSHI = Color(0.9098039215686275, 0.7137254901960784, 0.2784313725490196, 1) +AKE = Color(0.8, 0.3294117647058824, 0.2274509803921569, 1) +TOKIWA = Color(0.1058823529411765, 0.5058823529411765, 0.2431372549019608, 1) + +if __name__ == '__main__': + M = Match.read_from_json("D:\\code\\python\\swdata\\wos-data-new\\G302.json") + info = M.query('game', 'created').select('info').first()['info'] + conf = json.loads(info['config']) + game_end_at = int(info['game_end_at']) + P = {} + F = {} + R = 30 + for r in M.query('player', 'join').raw_data: + P[r['pid']] = Point(len(F) * FACE_WIDTH + FACE_INTERVAL, ROUND_HEIGHT / 2) + F[r['pid']] = 5 + + surface = SVGSurface("example.svg", len(P)*(FACE_WIDTH)+FACE_WIDTH, (game_end_at+2)*ROUND_HEIGHT) + context = Context(surface) + + for i in range(1, game_end_at + 2): + next_f = F.copy() + for r in M.query('action', 'done').where(lambda row: row['rno'] == i).raw_data: + draw_action_arrow(context, P[r['a']], P[r['b']], LINEWIDTH, 15, R, AKE.shade(r['tr'] / 1440) if r['act_a'] == 'D' else TOKIWA.shade(r['tr']/1440)) + draw_action_arrow(context, P[r['b']], P[r['a']], LINEWIDTH, 15, R, AKE.shade(r['tr'] / 1440) if r['act_b'] == 'D' else TOKIWA.shade(r['tr']/1440)) + next_f[r['a']] += conf['payoffs']["%s%s"%(r['act_a'], r['act_b'])][0] * r['tr'] / 1440.0 + next_f[r['b']] += conf['payoffs']["%s%s"%(r['act_a'], r['act_b'])][1] * r['tr'] / 1440.0 + draw_faces(context, P, F, R, LINEWIDTH) + for k in next_f.keys(): + F[k] = next_f[k] - conf['rounds']['consumption'] + P[k].rel_move_to(0, ROUND_HEIGHT) + + + surface.finish() diff --git a/island/__init__.py b/island/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/island/match.py b/island/match.py new file mode 100644 index 0000000..8741749 --- /dev/null +++ b/island/match.py @@ -0,0 +1,98 @@ +""" +一场比赛的数据 +""" +import json + +class Match: + """Match""" + + def __init__(self, raw, dtype='json'): + """ + :param json_string: string represents data in json format + """ + if dtype == 'json': + self.raw_data = json.loads(raw) + self.dtype = 'json' + else: + self.raw_data = raw + self.dtype = 'mid' + + def query(self, cat, act): + """ + start a query + eg. match.query('game', 'created') + :param cat: category + "param act: action + """ + if self.dtype == 'mid': + raise RuntimeError("Query on intermediate result.") + result = [] + for entry in self.raw_data: + if entry['cat'] == cat and entry['act'] == act: + result.append(entry) + return Match(result, dtype='mid') + + def where(self, where_expr): + """ + add some condition + eg. match.query('player', 'join').where(lambda i: i['pid']==9527) + """ + if self.dtype != 'mid': + raise RuntimeError("Where query on raw data.") + return Match([item for item in self.raw_data if where_expr(item)], dtype='mid') + + def orderby(self, key): + """ + sort it! + eg. match.query('player', 'join').where(lambda i: i['pid']<9527).orderby('created_at') + """ + if self.dtype != 'mid': + raise RuntimeError("Orderby query on raw data.") + + return Match(sorted(self.raw_data, key=lambda x: x[key]), dtype='mid') + + def select(self, key1, *args): + """ + select some columns + eg. match.query('player', 'join') + .select('pid', 'created_at') + .where(lambda i: i['pid']<9527) + .orderby('created_at') + """ + if self.dtype != 'mid': + raise RuntimeError("select query on raw data.") + + result = [] + + keys = [key1] + for k in args: + keys.append(k) + + for entry in self.raw_data: + dct = dict.fromkeys(keys) + for k in keys: + dct[k] = entry[k] + result.append(dct) + + return Match(result, dtype='mid') + + def first(self): + """ + return first result + """ + if self.dtype != 'mid': + raise RuntimeError("first query on raw data.") + + rawl = len(self.raw_data) + return self.raw_data[0] if rawl > 0 else None + + @staticmethod + def read_from_json(json_path): + """ + 从json_path读取json文件,并返回Match + :param json_path: path to json file + """ + json_string = '' + with open(json_path, 'r', encoding='utf-8') as file: + json_string = file.read() + return Match(json_string) diff --git a/island/matches.py b/island/matches.py new file mode 100644 index 0000000..b0e2ed2 --- /dev/null +++ b/island/matches.py @@ -0,0 +1,13 @@ +from pathlib import Path +from .match import Match + + +class Matches: + def __init__(self, logdir): + self.data = [] + self.names = [] + for file in Path(logdir).iterdir(): + if Path(file).suffix == '.json': + self.data.append(Match.read_from_json(str(file))) + self.names.append(Path(file).stem) + diff --git a/neighbors_per_round.py b/neighbors_per_round.py new file mode 100644 index 0000000..8467e2a --- /dev/null +++ b/neighbors_per_round.py @@ -0,0 +1,45 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches + +matches = Matches('wos-data-new') +max_round = 17 + +coopr = [] +yerr_min = [] +yerr_max = [] +x = [] +bx = [] + +survivals = {} +with open('winner.json','r') as f: + survivals = json.load(f) + +for i in range(max_round): + co = [] + for j in range(len(matches.data)): + nodes = set() + rows = matches.data[j].query('action', 'done').where(lambda x: x['rno']==i+1).raw_data + for row in rows: + nodes.add(row['a']) + nodes.add(row['b']) + + if rows: + co.append(float(len(rows) * 2) / float(len(nodes))) + + bx.append(co) + + if co: + coopr.append(sum(co) / len(co)) + + yerr_min.append(coopr[-1] - min(co)) + yerr_max.append(max(co) - coopr[-1]) + print("%f, %f, %f"%(yerr_min[-1], yerr_max[-1], coopr[-1])) + x.append(i+1) + +plt.figure() +# plt.errorbar(x, coopr, yerr=[yerr_min, yerr_max], fmt='o', capsize=4) +plt.boxplot(bx, showmeans=True, meanline=True) +plt.show() +# plt.savefig('graph/co_per_round.png') \ No newline at end of file diff --git a/plot_act_rnd_per_file.py b/plot_act_rnd_per_file.py new file mode 100644 index 0000000..3122ff0 --- /dev/null +++ b/plot_act_rnd_per_file.py @@ -0,0 +1,43 @@ +import json +from pathlib import Path + +import numpy as np +from matplotlib import pyplot as plt +from matplotlib.ticker import MultipleLocator + + +def read_and_plot(json_file): + graph_dir = Path('/Users/wjsjwr/lab/code/swdata/graph/') + dpath = Path(json_file) + with open(json_file, 'r') as f: + data = json.load(f) + + actions = '' + rnds = '' + for d in data: + if d['cat'] == 'game' and d['act'] == 'created': + actions = np.zeros((2, int(d['info']['game_end_at'])), dtype=np.int32) + rnds = list(range(1,int(d['info']['game_end_at'])+1)) + break + + for d in data: + if d['cat'] == 'action' and d['act'] == 'done': + actions[0 if d['act_a'] == 'C' else 1, int(d['rno'])-1] += 1 + actions[0 if d['act_b'] == 'C' else 1, int(d['rno'])-1] += 1 + + plt.clf() + lines = [] + lg = ['C', 'D'] + l, = plt.plot(rnds, actions[0,:], color='#FF358B', linewidth=1) + lines.append(l) + l, = plt.plot(rnds, actions[1,:], color='#01B0F0', linewidth=1) + lines.append(l) + plt.figlegend(lines, lg, numpoints=1, loc='upper right') + fname = "act_rnd_%s.eps" % str(dpath.stem) + plt.savefig(str(graph_dir / fname)) + +itr = Path('/Users/wjsjwr/lab/wos-data-new/') +for d in itr.iterdir(): + if d.suffix == '.json': + read_and_plot(str(d)) + print(str(d)) diff --git a/plot_defect_alive.py b/plot_defect_alive.py new file mode 100644 index 0000000..03f44d8 --- /dev/null +++ b/plot_defect_alive.py @@ -0,0 +1,55 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches + +matches = Matches('wos-data-new') +max_round = 17 + +alive = [] +yerr_min = [] +yerr_max = [] +x = [] +al_al = [] + +survivals = {} +with open('winner.json','r') as f: + survivals = json.load(f) + +for i in range(max_round): + defects = [] + for j in range(len(matches.data)): + defector = set() + for row in matches.data[j].query('action', 'done').where(lambda x: x['rno']==i+1 and (x['act_a']=='D' or x['act_b']=='D')).raw_data: + if row['act_a']=='D': + defector.add(row['a']) + if row['act_b'] == 'D': + defector.add(row['b']) + + if defector: + # print("[%d,%d] %s" % (i,j,str(defector))) + incr = 0 + for k in survivals[matches.names[j]]: + if k in defector: + incr += 1 + # print(k) + defects.append(float(incr) / float(len(defector))) + + print(i) + print(defects) + if defects: + + al_al.append(defects) + alive.append(sum(defects) / len(defects)) + yerr_min.append(alive[-1] - min(defects)) + yerr_max.append(max(defects) - alive[-1]) + print("%f, %f, %f"%(yerr_min[-1], yerr_max[-1], alive[-1])) + x.append(i+1) + else: + al_al.append([]) + +plt.figure() +# plt.errorbar(x, alive, yerr=[yerr_min, yerr_max], fmt='o', capsize=4) +plt.boxplot(al_al, showmeans=True, meanline=True) +plt.show() +# plt.savefig('graph/survive_after_defect.png') \ No newline at end of file diff --git a/unlink_has_neighbor.py b/unlink_has_neighbor.py new file mode 100644 index 0000000..c6ff7d8 --- /dev/null +++ b/unlink_has_neighbor.py @@ -0,0 +1,53 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches + +matches = Matches('wos-data-new') + +labels = ['has neighbor', 'no neighbor'] +percents = [0.0, 0.0] + +for m in matches.data: + info = m.query('game', 'created').select('info').first()['info'] + conf = json.loads(info['config']) + game_end_at = int(info['game_end_at']) + + for row in m.query('action', 'done').where(lambda x: x['act_a'] == 'D' or x['act_b'] == 'D').raw_data: + if row['rno'] == game_end_at: + print(row) + continue + if row['act_a'] == 'D': + a = row['a'] + b = row['b'] + n = m.query('action', 'done').where(lambda y: ((y['a'] == a and y['b'] == b) or (y['a'] == b and y['b'] == a)) and y['rno'] == row['rno'] + 1).raw_data + if n: + pass + else: + o = m.query('action', 'done').where(lambda y: (y['b'] == b or y['a'] == b) and y['rno'] == row['rno'] + 1).raw_data + if o: + percents[0] += 1 + else: + percents[1] += 1 + if row['act_b'] == 'D': + a = row['a'] + b = row['b'] + n = m.query('action', 'done').where(lambda y: ((y['a'] == a and y['b'] == b) or (y['a'] == b and y['b'] == a)) and y['rno'] == row['rno'] + 1).raw_data + if n: + pass + else: + o = m.query('action', 'done').where(lambda y: (y['b'] == a or y['a'] == a) and y['rno'] == row['rno'] + 1).raw_data + if o: + percents[0] += 1 + else: + percents[1] += 1 + +_all = sum(percents) / 100 +percents[0] /= _all +percents[1] /= _all + +plt.figure() +plt.pie(percents, labels=labels, autopct='%1.1f%%', startangle=90) +plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. +plt.show() +# plt.savefig('graph/unlink_has_neighbor.png') \ No newline at end of file diff --git a/winner.json b/winner.json new file mode 100644 index 0000000..c4d06d9 --- /dev/null +++ b/winner.json @@ -0,0 +1 @@ +{"G153": [], "G203": [], "G254": [], "G272": [3170], "G285": [], "G295": [], "G299": [3558, 3559, 3563, 3575], "G302": [3649], "G307": [3896, 3901], "G318": [3965, 3967, 3970, 3973], "G337": [], "G341": [4462, 4463, 4464, 4476], "G349": [4558, 4559], "G354": [4614, 4615, 4616, 4618, 4623, 4624], "G54": [], "G68": [], "G72": [], "G75": [], "G86": []} \ No newline at end of file