Skip to content


Subversion checkout URL

You can clone with
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

156 lines (137 sloc) 5.456 kB
import pymongo
from collections import defaultdict
#module-level things like this can break
c = pymongo.Connection()
games =
plays = c.test.plays
plays_by_turn = c.test.plays_by_turn
plays_by_turn.ensure_index([('key', 1), ('turn', 1)])
BASIC_CARDS= ['Copper', 'Silver', 'Gold', 'Potion', 'Platinum',
'Estate', 'Duchy', 'Province', 'Colony', 'Curse']
def analyze_plays():
Analyze the card plays in all games.
counter = 0
for game in games.find():
counter += 1
for deck in game['decks']:
if counter % 10 == 0:
if counter % 1000 == 100:
# instant gratification!
def compute_all_stats():
After analyze_plays has been run, augment the combo data with interesting
print('Collecting stats...')
freqs = {}
total_freqs = defaultdict(float)
for combo in plays.find():
cards = tuple(combo['cards'])
freqs[cards] = combo['freq']
total_freqs[len(cards)] += combo['freq']
rates = {}
for cards in freqs:
rates[cards] = freqs[cards] / total_freqs[len(cards)]
for collection in (plays, plays_by_turn):
for combo in collection.find():
freq = float(combo['freq'])
cards = tuple(combo['cards'])
interestingness = _relative_rate(cards, rates)
# Interesting TODO: split the credit between multiple simultaneous
# combos, instead of giving all of them all the credit
combo['rate'] = rates[cards]
combo['interestingness'] = interestingness
combo['win_rate'] = combo['win_points'] / freq
combo['vp_rate'] = combo['victory_points'] / freq
combo['money_rate'] = combo['money'] / freq
combo['combo_score'] = combo['interestingness'] * combo['win_rate']
def analyze_deck(deck):
Analyze the card plays in a single recorded deck, adding results to the
`plays` and `plays_by_turn` collections.
win_points = deck['win_points']
victory_points = deck['points']
for turn in deck['turns']:
money = turn.get('money', 0)
plays = turn.get('plays', [])
turn_number = turn['number']
# Some bookkeeping to make sure we count repeated combos in a way
# that matches intuition. For example:
# [Festival, Smithy] has 1 instance of the combo (Festival, Smithy)
# [Festival, Smithy, Smithy] also has 1 instance
# [Festival, Smithy, Festival, Smithy] has 2 instances
multiplicity = defaultdict(int)
for card in plays:
if card not in BASIC_CARDS:
multiplicity[card] += 1
unique_plays = multiplicity.keys()
for i1, card1 in enumerate(unique_plays):
_record_play((card1,), win_points, victory_points,
money, turn_number, multiplicity)
for i2, card2 in enumerate(unique_plays[i1+1:]):
_record_play((card1, card2),
win_points, victory_points,
money, turn_number, multiplicity)
for i3, card3 in enumerate(unique_plays[i1+i2+2:]):
assert card3 != card1
assert card3 != card2
_record_play((card1, card2, card3),
win_points, victory_points,
money, turn_number, multiplicity)
def _record_play(cards, win_points, victory_points,
money, turn_number, multiplicity):
occur = min(multiplicity[card] for card in cards)
key = '+'.join(cards)
increases = {'freq': occur,
'win_points': win_points * occur,
'victory_points': victory_points * occur,
'money': money * occur,
{'key': key},
{'$set': {'cards': list(cards), 'ncards': len(cards)},
'$inc': increases},
# {'key': key, 'turn': turn_number},
# {'$set': {'cards': list(cards), 'ncards': len(cards)},
# '$inc': increases},
# upsert=True,
# safe=False
def _relative_rate(combo, rates):
How much more often than expected this combo is played.
This is a quick hack for now. The functions for relative bigram and trigram
frequency from NLP would be more effective, but I don't feel like looking
them up and implementing them right now. --Rob
if len(combo) == 1:
expected = 1.0
elif len(combo) == 2:
expected = rates[combo[0:1]] * rates[combo[1:2]]
elif len(combo) == 3:
expected = max(rates[(combo[0],)] * rates[(combo[1], combo[2])],
rates[(combo[1],)] * rates[(combo[0], combo[2])],
rates[(combo[2],)] * rates[(combo[0], combo[1])]
#FIXME: this falls through if not 1/2/3
return rates[combo] / expected
if __name__ == '__main__':
print('Analyzing games...')
Jump to Line
Something went wrong with that request. Please try again.