-
Notifications
You must be signed in to change notification settings - Fork 22
/
analyze.py
147 lines (118 loc) · 5.36 KB
/
analyze.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/python
""" Compute correlations between when/how many of a card is gained and wins."""
from __future__ import division
import os
import card_info
from stats import MeanVarStat
from game import Game
import incremental_scanner
import pymongo
import collections
import simplejson as json
from primitive_util import PrimitiveConversion, ConvertibleDefaultDict
import utils
class CardStatistic(PrimitiveConversion):
""" Per card statistics.
win_weighted_accum_turn: Dictionary keyed by turn that correlates
winning and gaining/buying the card on a given turn. It is
weighted in the sense that if a card is bought twice in a given
turn, it counts twice for that turn.
win_diff_accum: Dictionary keyed by relative card advantage that
correlates winning and have an advantage/disadvantage in the
number of a given card. Card advantages are rounded relative
to the average number gained/bought by other players through the
game.
"""
def __init__(self):
self.available = 0
self.win_any_accum = MeanVarStat()
self.win_weighted_accum = MeanVarStat()
self.win_weighted_accum_turn = ConvertibleDefaultDict(MeanVarStat, int)
self.win_diff_accum = ConvertibleDefaultDict(MeanVarStat, int)
class GamesAnalysis(PrimitiveConversion):
""" A collection of CardStatistics for every card in the deck. """
def __init__(self):
self.card_stats = ConvertibleDefaultDict(CardStatistic)
self.num_games = 0
self.max_game_id = ''
def analyze_game(self, game):
""" Aggregate information about game into this object.
game: game.Game object to analyze.
"""
self.num_games += 1
seen_cards_players = set()
self.max_game_id = max(self.max_game_id, game.get_id())
for card in game.get_supply() + card_info.EVERY_SET_CARDS:
self.card_stats[card].available += len(game.get_player_decks())
accumed_by_player = collections.defaultdict(lambda : collections.defaultdict(int))
for turn in game.get_turns():
deck = turn.get_player()
turnno = turn.get_turn_no()
for card in turn.player_accumulates():
per_card_stat = self.card_stats[card]
if (deck, card) not in seen_cards_players:
seen_cards_players.add((deck, card))
per_card_stat.win_any_accum.add_outcome(deck.WinPoints())
per_card_stat.win_weighted_accum.add_outcome(deck.WinPoints())
per_card_stat.win_weighted_accum_turn[turnno].add_outcome(
deck.WinPoints())
accumed_by_player[deck][card] += 1
for deck, card_accum_dict in accumed_by_player.iteritems():
total_other_decks = collections.defaultdict(int)
odeck_count = 0
for other_deck, other_accum in accumed_by_player.iteritems():
if other_deck != deck:
odeck_count += 1
for card in other_accum:
total_other_decks[card] += other_accum[card]
assert odeck_count != 0, game.isotropic_url()
for card in set(card_accum_dict.keys() + total_other_decks.keys()):
per_card_stat = self.card_stats[card]
other_avg_freq = total_other_decks[card] / odeck_count
card_diff_index = int(card_accum_dict[card] - other_avg_freq)
per_card_stat.win_diff_accum[card_diff_index].add_outcome(
deck.WinPoints())
def main():
""" Update analysis statistics. By default, do so incrementally, unless
--noincremental argument is given."""
parser = utils.incremental_max_parser()
parser.add_argument('--output_collection_name', default='analysis')
args = parser.parse_args()
conn = pymongo.Connection()
database = conn.test
games = database.games
output_collection_name = args.output_collection_name
output_collection = database[output_collection_name]
game_analysis = GamesAnalysis()
scanner = incremental_scanner.IncrementalScanner(output_collection_name,
database)
if args.incremental:
utils.read_object_from_db(game_analysis, output_collection, '')
else:
scanner.reset()
output_file_name = 'static/output/all_games_card_stats.js'
if not os.path.exists('static/output'):
os.makedirs('static/output')
print scanner.status_msg()
for idx, raw_game in enumerate(scanner.scan(games, {})):
try:
if idx % 1000 == 0:
print idx
game_analysis.analyze_game(Game(raw_game))
if idx == args.max_games:
break
except int, exception:
print Game(raw_game).isotropic_url()
print exception
print raw_game
raise
game_analysis.max_game_id = scanner.get_max_game_id()
game_analysis.num_games = scanner.get_num_games()
utils.write_object_to_db(game_analysis, output_collection, '')
output_file = open(output_file_name, 'w')
output_file.write('var all_card_data = ')
json.dump(game_analysis.to_primitive_object(), output_file)
print scanner.status_msg()
scanner.save()
if __name__ == '__main__':
main()