swdata/eid_calc.py
2022-07-24 11:07:11 +08:00

179 lines
6.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
计算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()