swdata/eid_calc.py
2018-09-30 15:51:09 +08:00

182 lines
6.3 KiB
Python
Raw 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
import numpy as np
from island.match import Match
from island.matches import Matches
class Eid:
def __init__(self):
self.survivals = {}
with open('outputs/survivals.json','r') as f:
self.survivals = json.load(f)
self.neighbors = {}
with open('outputs/neighborhood.json', 'r') as f:
self.neighbors = json.load(f)
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
"""
ans = {}
sigma = 0.0
for p in self.survivals[m.name][str(r)]:
u, v = self.getVictims(m, r, p)
if u > 0:
e = max(0, min(1440, self.getTR2(m, r, p, self.getNeighborhood(m, r, p), v))) - u
ans[p] = e
sigma += e
return (sigma, ans)
def calc(self):
detail = {}
avgC = np.zeros(15)
avgS = np.zeros(15)
cnt = np.zeros(15)
for m in self.seasonClassic.data:
d = {}
maxr = int(m.query('game', 'created').first()['info']['game_end_at'])
for r in range(1, maxr+1):
sigma, ans = self.calcRoundData(m, r)
d[r] = ans
avgC[r-1] += sigma
cnt[r-1] += len(ans)
detail[m.name] = d
print(cnt)
for i in range(15):
if cnt[i] == 0:
cnt[i] = 1
avgC /= cnt
cnt = np.zeros(15)
for m in self.seasonSurvive.data:
d = {}
maxr = int(m.query('game', 'created').first()['info']['game_end_at'])
for r in range(1, maxr+1):
sigma, ans = self.calcRoundData(m, r)
d[r] = ans
avgS[r-1] += sigma
cnt[r-1] += len(ans)
detail[m.name] = d
print(cnt)
for i in range(15):
if cnt[i] == 0:
cnt[i] = 1
avgS /= cnt
with open('outputs/EID_CLASSIC.csv', 'w') as f:
csv.writer(f).writerow(avgC)
with open('outputs/EID_SURVIVE.csv', 'w') as f:
csv.writer(f).writerow(avgS)
with open('outputs/EID_detail.json', 'w') as f:
json.dump(detail, f)
if __name__ == '__main__':
e = Eid()
e.calc()