179 lines
6.1 KiB
Python
179 lines
6.1 KiB
Python
"""
|
||
计算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()
|