""" 计算E_{i,D} E_{i,D}=所有邻居的剩余时间 - (背叛对象的剩余时间 + 与背叛对象的上轮交互时间) =除去背叛对象的剩余时间 - 背叛对象的上一轮交互时间 输出: 1. json格式(详细) { "GID": { "RID": { "PID": EID, } } } 2. CSV格式(按轮平均值, CLASSIC/SURVIVE分别对应一个文件) """ import csv import json from functools import reduce from sre_constants import MAX_REPEAT from tkinter.tix import MAX import numpy as np from island.match import Match from island.matches import Matches MAX_ROUND = 28 class Eid: def __init__(self): self.details = {} self.survivals = {} with open('outputs/survivals_new.json','r') as f: self.survivals = json.load(f) self.neighbors = {} with open('outputs/neighborhood_new.json', 'r') as f: self.neighbors = json.load(f) self.seasons = [ dict(season=Matches('wos-data-2022-1', network_type='BA'), name='NEW_BA'), dict(season=Matches('wos-data-2022-1', network_type='WS'), name='NEW_WS') ] # self.seasonSurvive = Matches.from_profile('SURVIVE') # self.seasonClassic = Matches.from_profile('CLASSIC') def getNeighborTR(self, m, r, p, s, d): """ 获取该玩家所有邻居中,除去背叛对象的剩余时间 :param m: Match :param r: Round ID :param p: PID :param s: Survivals list(neighborhood) :param d: list of victim :returns: E_{i} """ truenb = [i for i in s if i not in d] trs = dict.fromkeys(truenb, 1440) req = m.query('action', 'request').where(lambda x: x['rno'] == r and x['from'] in truenb and x['to'] != p) for d in req.raw_data: trs[d['from']] -= d['tr'] for d in m.query('action', 'approve').where(lambda x: x['rno'] == r and x['from'] in truenb and x['to'] != p).raw_data: trs[d['from']] -= d['tr'] for d in m.query('action', 'cancel').where(lambda x: x['rno'] == r and x['from'] in truenb and x['to'] != p).raw_data: trs[d['from']] += req.where(lambda x: x['from'] == d['from'] and x['to'] == d['to'] and x['log_id'] < d['log_id']).orderby('log_id').raw_data[-1]['tr'] for d in m.query('action', 'deny').where(lambda x: x['rno'] == r and x['to'] in truenb and x['from'] != p).raw_data: trs[d['to']] += req.where(lambda x: x['from'] == d['to'] and x['to'] == d['from'] and x['log_id'] < d['log_id']).orderby('log_id').raw_data[-1]['tr'] return reduce(lambda x,y: x + max(0,min(y,1440)), trs.values(), 0) def getTR2(self, m, r, p, s, d): truenb = [i for i in s if i not in d] return reduce(lambda a, b: a + b['tr'], m.query('action', 'done').where(lambda x: x['rno'] == r and ((x['a'] in truenb and x['b'] == p)or(x['b']in truenb and x['a'] == p))).raw_data, 0) def getNeighborhood(self, m, r, p): """ 获取该玩家当轮存活邻居 :param m: Match :param r: Round ID :param p: PID :returns: Survivals list(neighborhood) """ if str(p) not in self.neighbors[m.name]: print("Alone(%d)!" % p) return [] return [i for i in self.survivals[m.name][str(r)] if i in self.neighbors[m.name][str(p)]] def getVictims(self, m, r, p): """ 获取该玩家当轮的背叛对象,以及与他们的博弈时间资源之和 :param m: Match :param r: Round ID :param p: PID :returns: sum of tr and a list of victim """ victim = [] ans = 0 for d in m.query('action', 'done').where(lambda x: x['rno'] == r-1 and (x['a'] == p or x['b'] == p)).raw_data: if d['a'] == p and d['act_a'] == 'D': victim.append(d['b']) ans += d['tr'] elif d['b'] == p and d['act_b'] == 'D': victim.append(d['a']) ans += d['tr'] return (ans, victim) def getVictims2(self, m, r, p): """ 获取该玩家当轮的背叛对象,以及与他们的博弈时间资源之和 ## 悲观假设背叛上一轮所有博弈对象 :param m: Match :param r: Round ID :param p: PID :returns: sum of tr and a list of victim """ victim = [] ans = 0 for d in m.query('action', 'done').where(lambda x: x['rno'] == r-1 and (x['a'] == p or x['b'] == p)).raw_data: victim.append(d['b'] if d['a'] == p else d['a']) ans += d['tr'] return (ans, victim) def calcRoundData(self, m, r): """ 计算某场比赛,某一轮的Eid值 :param m: Match :param r: Round ID :param p: PID :returns: an average value and a detail dict """ r += 1 ans = {} sigma = 0.0 for p in self.survivals[m.name][str(r)]: u, v = self.getVictims2(m, r, p) e = max(0, min(1440, self.getNeighborTR(m, r, p, self.getNeighborhood(m, r, p), v))) - u ans[p] = e sigma += e return (sigma, ans) def calc_season(self, season, name): """ calc E_i,D """ avg = np.zeros(MAX_ROUND) cnt = np.zeros(MAX_ROUND) for m in season.data: d = {} maxr = int(m.query('game', 'created').first()['info']['game_end_at']) for r in range(1, maxr): sigma, ans = self.calcRoundData(m, r) d[r] = ans avg[r-1] += sigma cnt[r-1] += len(ans) self.details[m.name] = d print(cnt) for i in range(MAX_ROUND): if cnt[i] == 0: cnt[i] = 1 avg /= cnt with open(f'outputs/EID_{name}.csv', 'w') as f: csv.writer(f).writerow(avg) return avg def calc(self): for s in self.seasons: self.calc_season(s['season'], s['name']) with open('outputs/EID_new_detail.json', 'w') as f: json.dump(self.details, f) if __name__ == '__main__': e = Eid() e.calc()