Example #1
0
    def test_initialization(self):
        """Test various ways of initializing card objects
        """
        card = dominioncards.get_card('Estate')
        self.assertEquals(card.singular, 'Estate')

        card = dominioncards.get_card('Card(Estate)')
        self.assertEquals(card.singular, 'Estate')
    def test_initialization(self):
        """Test various ways of initializing card objects
        """
        card = dominioncards.get_card('Estate')
        self.assertEquals(card.singular, 'Estate')


        card = dominioncards.get_card('Card(Estate)')
        self.assertEquals(card.singular, 'Estate')
Example #3
0
def check_game_sanity(game_val, log):
    """ Check if if game_val is self consistent.

    In particular, check that the end game player decks match the result of
    simulating deck interactions saved in game val."""

    global __problem_deck_index__

    supply = game_val.get_supply()
    # ignore known bugs.
    if set(supply).intersection(
        [get_card('Masquerade'),
         get_card('Black Market'),
         get_card('Trader')]):
        return True

    # TODO: add score sanity checking here
    last_state = None
    game_state_iterator = game_val.game_state_iterator()
    for game_state in game_state_iterator:
        last_state = game_state
    for player_deck in game_val.get_player_decks():
        parsed_deck_comp = player_deck.Deck()
        computed_deck_comp = last_state.get_deck_composition(
            player_deck.name())

        delete_keys_with_empty_vals(parsed_deck_comp)
        computed_dict_comp = dict(computed_deck_comp)
        delete_keys_with_empty_vals(computed_dict_comp)

        if parsed_deck_comp != computed_deck_comp:
            found_something_wrong = False
            for card in set(parsed_deck_comp.keys() +
                            computed_deck_comp.keys()):
                if parsed_deck_comp.get(card, 0) != \
                        computed_deck_comp.get(card, 0):
                    if not found_something_wrong:
                        __problem_deck_index__ += 1
                        log.debug('[%d] %18s %9s %9s', __problem_deck_index__,
                                  'card', 'from-data', 'from-sim')
                    log.debug('[%d] %-18s %9d %9d', __problem_deck_index__,
                              card, parsed_deck_comp.get(card, 0),
                              computed_deck_comp.get(card, 0))
                    found_something_wrong = True
            if found_something_wrong:
                try:
                    log.debug('[%d] insane game for %s %s: %s',
                              __problem_deck_index__, player_deck.name(),
                              game_val.get_id(),
                              ' '.join(map(str, game_val.get_supply())))
                except UnicodeEncodeError as e:
                    None
                return False
    return True
Example #4
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")  
        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))
        db = utils.get_mongo_database()
        selected_card = ''

        if 'card' in query_dict:
            selected_card = query_dict['card']

        results = db.trueskill_openings.find({'_id': {'$regex': '^open:'}})
        openings = list(results)
        card_list = dominioncards.opening_cards()
        def split_opening(o):
            ret = o['_id'][len('open:'):].split('+')
            if ret == ['']: return []

            # Convert the __repr__() representation stored in the
            # database to the singular version of the card name.
            return [dominioncards.get_card(card).singular for card in ret]

        if selected_card not in ('All cards', ''):
            openings = [o for o in openings if selected_card in 
                        split_opening(o)]
                        
        openings = [o for o in openings if split_opening(o)]
        for opening in openings:
            floor = opening['mu'] - opening['sigma'] * 3
            ceil = opening['mu'] + opening['sigma'] * 3
            opening['level_key'] = make_level_key(floor, ceil)
            opening['level_str'] = make_level_str(floor, ceil)
            opening['skill_str'] = skill_str(opening['mu'], opening['sigma'])
            opening['cards'] = split_opening(opening)
            opening['cards'].sort()
            opening['cards'].sort(key=lambda card: dominioncards.get_card(card).cost, reverse=True)
            costs = [str(dominioncards.get_card(card).cost) for card in opening['cards']]
            while len(costs) < 2:
                costs.append('-')
            opening['cost'] = '/'.join(costs)

        openings.sort(key=lambda opening: opening['level_key'])
        openings.reverse()
        if selected_card == '':
            openings = [op for op in openings
                        if op['level_key'][0] != 0
                        or op['_id'] == ['Silver', 'Silver']]

        render = web.template.render('')
        return render.openings_template(openings, card_list, selected_card)
Example #5
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")  
        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))
        db = utils.get_mongo_database()
        selected_card = ''

        if 'card' in query_dict:
            selected_card = query_dict['card']

        results = db.trueskill_openings.find({'_id': {'$regex': '^open:'}})
        openings = list(results)
        card_list = dominioncards.opening_cards()
        def split_opening(o):
            ret = o['_id'][len('open:'):].split('+')
            if ret == ['']: return []

            # Convert the __repr__() representation stored in the
            # database to the singular version of the card name.
            return [dominioncards.get_card(card).singular for card in ret]

        if selected_card not in ('All cards', ''):
            openings = [o for o in openings if selected_card in 
                        split_opening(o)]
                        
        openings = [o for o in openings if split_opening(o)]
        for opening in openings:
            floor = opening['mu'] - opening['sigma'] * 3
            ceil = opening['mu'] + opening['sigma'] * 3
            opening['level_key'] = make_level_key(floor, ceil)
            opening['level_str'] = make_level_str(floor, ceil)
            opening['skill_str'] = skill_str(opening['mu'], opening['sigma'])
            opening['cards'] = split_opening(opening)
            opening['cards'].sort()
            opening['cards'].sort(key=lambda card: dominioncards.get_card(card).cost, reverse=True)
            costs = [str(dominioncards.get_card(card).cost) for card in opening['cards']]
            while len(costs) < 2:
                costs.append('-')
            opening['cost'] = '/'.join(costs)

        openings.sort(key=lambda opening: opening['level_key'])
        openings.reverse()
        if selected_card == '':
            openings = [op for op in openings
                        if op['level_key'][0] != 0
                        or op['_id'] == ['Silver', 'Silver']]

        render = web.template.render('')
        return render.openings_template(openings, card_list, selected_card)
Example #6
0
        def split_opening(o):
            ret = o['_id'][len('open:'):].split('+')
            if ret == ['']: return []

            # Convert the __repr__() representation stored in the
            # database to the singular version of the card name.
            return [dominioncards.get_card(card).singular for card in ret]
Example #7
0
        def split_opening(o):
            ret = o['_id'][len('open:'):].split('+')
            if ret == ['']: return []

            # Convert the __repr__() representation stored in the
            # database to the singular version of the card name.
            return [dominioncards.get_card(card).singular for card in ret]
Example #8
0
def check_game_sanity(game_val, log):
    """ Check if if game_val is self consistent.

    In particular, check that the end game player decks match the result of
    simulating deck interactions saved in game val."""

    global __problem_deck_index__

    supply = game_val.get_supply()
    # ignore known bugs.
    if set(supply).intersection([get_card('Masquerade'), get_card('Black Market'), get_card('Trader')]):
        return True

    # TODO: add score sanity checking here
    last_state = None
    game_state_iterator = game_val.game_state_iterator()
    for game_state in game_state_iterator:
        last_state = game_state
    for player_deck in game_val.get_player_decks():
        parsed_deck_comp = player_deck.Deck()
        computed_deck_comp = last_state.get_deck_composition(
            player_deck.name())

        delete_keys_with_empty_vals(parsed_deck_comp)
        computed_dict_comp = dict(computed_deck_comp)
        delete_keys_with_empty_vals(computed_dict_comp)

        if parsed_deck_comp != computed_deck_comp:
            found_something_wrong = False
            for card in set(parsed_deck_comp.keys() +
                            computed_deck_comp.keys()):
                if parsed_deck_comp.get(card, 0) != \
                        computed_deck_comp.get(card, 0):
                    if not found_something_wrong:
                        __problem_deck_index__ += 1
                        log.debug('[%d] %18s %9s %9s', __problem_deck_index__, 'card', 'from-data', 'from-sim')
                    log.debug('[%d] %-18s %9d %9d', __problem_deck_index__, card, parsed_deck_comp.get(card, 0),
                              computed_deck_comp.get(card, 0))
                    found_something_wrong = True
            if found_something_wrong:
                try:
                    log.debug('[%d] insane game for %s %s: %s', __problem_deck_index__, player_deck.name(), game_val.get_id(),
                              ' '.join(map(str, game_val.get_supply())))
                except UnicodeEncodeError, e:
                    None
                return False
Example #9
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")
        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))

        card_list = sorted(set(dominioncards.all_cards()) - 
                           set(dominioncards.TOURNAMENT_WINNINGS))

        card_x_card = dominioncards.get_card(query_dict.get('card_x', 'Minion'))
        card_y_card = dominioncards.get_card(query_dict.get('card_y', 'Chapel'))
        card_x = str(card_x_card)
        card_y = str(card_y_card)

        if card_x < card_y:
            db_id = card_x + ':' + card_y
            swap_x_and_y = False
        else:
            db_id = card_y + ':' + card_x
            swap_x_and_y = True

        db = utils.get_mongo_database()
        db_val = db.optimal_card_ratios.find_one({'_id': db_id})

        if not db_val:
            return 'No stats for "' + card_x + '" and "' + card_y + '".'

        tracker = DBCardRatioTracker()
        tracker.from_primitive_object(db_val)

        num_games = sum(meanvarstat.frequency() for meanvarstat 
                        in tracker.final.itervalues())
        num_games_threshold = int(round(num_games * .002))
        final_table = self.getHtmlTableForStats(
            tracker.final, swap_x_and_y, num_games, num_games_threshold)

        num_games = max(meanvarstat.frequency() for meanvarstat 
                        in tracker.progressive.itervalues())
        num_games_threshold = int(round(num_games * .002))
        progressive_table = self.getHtmlTableForStats(
            tracker.progressive, swap_x_and_y, num_games, num_games_threshold)

        render = web.template.render('')
        return render.optimal_card_ratios_template(
            card_list, card_x_card, card_y_card, final_table, progressive_table)
Example #10
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")
        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))

        card_list = sorted(set(dominioncards.all_cards()) - 
                           set(dominioncards.TOURNAMENT_WINNINGS))

        card_x_card = dominioncards.get_card(query_dict.get('card_x', 'Minion'))
        card_y_card = dominioncards.get_card(query_dict.get('card_y', 'Chapel'))
        card_x = str(card_x_card)
        card_y = str(card_y_card)

        if card_x < card_y:
            db_id = card_x + ':' + card_y
            swap_x_and_y = False
        else:
            db_id = card_y + ':' + card_x
            swap_x_and_y = True

        db = utils.get_mongo_database()
        db_val = db.optimal_card_ratios.find_one({'_id': db_id})

        if not db_val:
            return 'No stats for "' + card_x + '" and "' + card_y + '".'

        tracker = DBCardRatioTracker()
        tracker.from_primitive_object(db_val)

        num_games = sum(meanvarstat.frequency() for meanvarstat 
                        in tracker.final.itervalues())
        num_games_threshold = int(round(num_games * .002))
        final_table = self.getHtmlTableForStats(
            tracker.final, swap_x_and_y, num_games, num_games_threshold)

        num_games = max(meanvarstat.frequency() for meanvarstat 
                        in tracker.progressive.itervalues())
        num_games_threshold = int(round(num_games * .002))
        progressive_table = self.getHtmlTableForStats(
            tracker.progressive, swap_x_and_y, num_games, num_games_threshold)

        render = web.template.render('')
        return render.optimal_card_ratios_template(
            card_list, card_x_card, card_y_card, final_table, progressive_table)
Example #11
0
def parse_supply(log_lines):
    line = log_lines.pop(0)
    supply_cards_text = line.split(', ')
    supply_cards_text[0] = supply_cards_text[0].replace('Supply cards: ','')
    supply_cards = []
    for card_name in supply_cards_text:
        try:
            card = get_card(card_name)
        except KeyError, exception:
            raise parse_common.ParsingError('%s is not a card in the supply!'
                                            % card_name)
        supply_cards.append(card.index)
Example #12
0
def capture_cards(line):
    """ Given a line of text from isotropic, extract the cards.

    line: string like 'Rob plays a <span class=card-none>Minion</span>.'
    returns: list of the card objects, eg, [Minion]
    """
    def _as_int_or_1(string_val):
        try:
            return int(string_val)
        except ValueError:
            return 1

    cards = []
    card_sections = SPLIT_COMMA_AND_RE.split(line)
    for sect in card_sections:
        split_at_span = sect.split('<span')
        if not split_at_span:
            continue
        first = split_at_span[0]
        split_first = first.split()
        if not split_first:
            mult = 1
        else:
            mult = _as_int_or_1(split_first[-1])

        for subsect in split_at_span:
            start_of_end_span = subsect.find('</span')
            if start_of_end_span == -1:
                continue
            end_of_begin_span = subsect.rfind('>', 0, start_of_end_span)
            if end_of_begin_span == -1:
                continue
            maybe_plural = subsect[end_of_begin_span + 1:
                                   start_of_end_span]
            if maybe_plural == '&diams;':
                continue
            try:
                card = get_card(maybe_plural)
            except KeyError, exception:
                raise ParsingError('Failed to find card in line: %s' % line)
            cards.extend([card] * mult)
Example #13
0
    def __init__(self, **args):
        self.exact_names = []
        self.players_restrict = []
        self.kingdom_restrict = []
        self.limit = 200
        self.debug_level = args.get('debug', 0)

        if 'p1_name' in args:
            self._add_name(args['p1_name'])
        if 'p2_name' in args:
            self._add_name(args['p2_name'])
        if 'kingdom' in args:
            self.kingdom_restrict = []
            for k in args['kingdom'].split(','):
                card = dominioncards.get_card(k.strip())
                self.kingdom_restrict.append(card.index)

        self.db_query = {}
        if self.players_restrict:
            self.db_query[PLAYERS] = {'$all': self.players_restrict}

        if self.kingdom_restrict:
            self.db_query[SUPPLY] = {'$all': self.kingdom_restrict}
Example #14
0
def capture_cards(line, return_dict=False):
    """ Given a section of text from goko, extract the cards.

    line: string like 'plays 1 Silver, 3 Copper'
    returns: list of the card objects, eg, [Silver, Copper, Copper, Copper]
    """
    for kw in KEYWORDS:
        line=line.replace(kw, '')


    if return_dict:
        cards = {}
    else:
        cards = []

    if EMPTY_LINE_RE.match(line):
        return cards

    card_sections = COMMA_SPLIT_RE.split(line)
    for sect in card_sections:
        multiple = NUMBER_CARD_RE.match(sect)
        if multiple:
            mult = int(multiple.group(1))
            sect = multiple.group(2)
        else:
            mult = 1

        try: 
            card = get_card(sect)
        except KeyError, exception:
            raise parse_common.ParsingError('Failed to find card in line: %s'
                                             % line)
        if return_dict:
            cards[str(card.index)]=mult
        else:
            cards.extend([card] * mult)
Example #15
0
 def str_card_index(self, card_name):
     card = dominioncards.get_card(card_name)
     return str(card.index)
Example #16
0
        diamond_loc = chunk.find(u'▼')
        if diamond_loc != -1:
            start_point_loc = max(chunk.rfind('(', 0, diamond_loc - 1),
                                  chunk.rfind(' ', 0, diamond_loc - 1))
            vp_tokens = int(chunk[start_point_loc + 1:diamond_loc - 1])

        card_list_chunks = deck_contents[
            deck_contents.find(']') + 1:].replace(',', ' ')
        card_blobs = [x for x in card_list_chunks.split('</span>') if
                      '<span' in x]
        deck_comp = {}
        for card_blob in card_blobs:
            right_bracket_index = card_blob.find('>')
            card_name = card_blob[right_bracket_index + 1:]
            try:
                card = get_card(card_name)
            except KeyError, exception:
                raise ParsingError("Failed to get card. chunk: '%s', card_name: '%s', card_blob: '%s'" % \
                                       (chunk, card_name, card_blob[right_bracket_index - 10:]))
            card_quant = int(card_blob.split()[0])
            deck_comp[str(card.index)] = card_quant
    #FIXME: deck_comp is undefined if there's no vp_list
    return {NAME: name, POINTS: points, RESIGNED: resigned,
            DECK: deck_comp, VP_TOKENS: vp_tokens}

def parse_decks(decks_blob):
    """ Parse and return a list of decks"""
    deck_blobs = [s for s in decks_blob.split('\n\n') if s]
    return [parse_deck(deck_blob) for deck_blob in deck_blobs]

VETO_RE = re.compile('(.*) vetoes (.*)\.')
Example #17
0
 def str_card_index(self, card_name):
     card = dominioncards.get_card(card_name)
     return str(card.index)
Example #18
0
def parse_turn(turn_blob, names_list):
    """ Parse the information from a given turn.

    Return a dict containing the following fields.  If any of the fields have
    a value that evaluates to False, do not keep it.

    name: player name.
    number: 1 indexed turn number.
    plays: List of cards played.
    buys: List of cards bought.
    gains: List of cards gained.
    trashes: List of cards trashed.
    returns: List of cards returned.
    ps_tokens: Number of pirate ship tokens gained.
    vp_tokens: Number of victory point tokens gained.
    money: Amount of money available during entire buy phase.
    opp: Dict keyed by opponent index in names_list, containing dicts with trashes/gains.
    """
    lines = turn_blob.strip().split('\n')
    header = lines[0]
    parsed_header = parse_turn_header(header, names_list)

    poss, outpost = False, False

    if 'pname' in parsed_header:
        possessee_name = parsed_header['name']
        possessee_index = names_list.index(possessee_name)
        poss = True
    if 'outpost' in parsed_header:
        outpost = True

    ret = {GAINS: [], TRASHES: [], BUYS: []}
    plays = []
    returns = []
    turn_money = 0
    vp_tokens = 0
    ps_tokens = 0
    opp_turn_info = collections.defaultdict(lambda: {GAINS: [],
                                                     TRASHES: [],
                                                     BUYS: []})
    tracker = PlayerTracker()

    for line_idx, line in enumerate(lines):
        active_player = tracker.get_active_player(line)
        if active_player == tracker.current_player():
            targ_obj = ret
        else:
            # Stop using the player's name here, as it is used as a
            # key name in a dict, which can't be stored in MongoDB if
            # it contains a dot ('.') or starts with a dollar
            # sign. Instead, use the player index number so we can
            # extract the name later.
            #
            # targ_obj = opp_turn_info[names_list[active_player]]
            targ_obj = opp_turn_info[str(active_player)]

        has_trashing = KW_TRASHING in line
        has_trashes = KW_TRASHES in line
        has_gaining = KW_GAINING in line
        orig_buys_len = len(targ_obj.get(BUYS, []))
        orig_gains_len = len(targ_obj.get(GAINS, []))

        did_trading_post_gain = False

        if has_trashes:
            if has_gaining:
                # Trading post turn, first trashes, then gaining
                gain_start = line.find(KW_GAINING)
                targ_obj[TRASHES].extend(capture_cards(line[:gain_start]))
                targ_obj[GAINS].extend(capture_cards(line[gain_start:]))
                did_trading_post_gain = True
            else:
                targ_obj[TRASHES].extend(capture_cards(line))
        if KW_WITH_A in line:
            if KW_REPLACING in line:
                new_gained_portion = line[line.find(KW_WITH_A):]
                targ_obj[GAINS].extend(capture_cards(new_gained_portion))
        if KW_PLAYS in line or KW_PLAYING in line:
            plays.extend(capture_cards(line))
        if has_gaining and not did_trading_post_gain:
            if KW_ANOTHER_ONE in line: # mints a gold gaining another one
                targ_obj[GAINS].extend(capture_cards(line))
            else:
                # gaining always associated with current player?
                targ_obj[GAINS].extend(
                    capture_cards(line[line.find(KW_GAINING):]))
        if KW_BUYS in line:
            targ_obj[BUYS].extend(capture_cards(line))
        if KW_GAINS_THE in line:
            targ_obj[GAINS].extend(capture_cards(line))
        if has_trashing:
            if KW_REVEALS in lines[line_idx - 1] and not KW_DRAWS in line:
                targ_obj[TRASHES].extend(capture_cards(lines[line_idx - 1]))
            if KW_REVEALING in line or KW_REVEALS in line:
                # reveals watchtower trashing ...
                # noble brigand reveals xx, yy and trashes yy
                trashed = capture_cards(line[line.find(KW_TRASHING):])
                targ_obj[TRASHES].extend(trashed)
            else:
                rest = line
                if KW_GAINING in line:
                    rest = line[:line.find(KW_GAINING)]
                targ_obj[TRASHES].extend(capture_cards(rest))
        if KW_GAINS_A in line or KW_GAMES_A in line:
            if KW_TOKEN in line:
                assert get_card('Pirate Ship') in capture_cards(line), 'Pirate ship not in line'
                ps_tokens += 1
            else:
                rest = line[max(line.find(KW_GAINS_A), line.find(KW_GAMES_A)):]
                targ_obj[GAINS].extend(capture_cards(rest))
        if KW_IS_TRASHED in line:
            # Saboteur after revealing cards, name not mentioned on this line.
            cards = capture_cards(line)
            targ_obj[TRASHES].extend(cards)
        if KW_REVEALS in line:
            card_revealed = capture_cards(line)

            # arg, ambassador requires looking at the next line to figure
            # out how many copies were returned
            if (card_revealed and line_idx + 1 < len(lines) and
                KW_RETURNING in lines[line_idx + 1] and not
                KW_REVEALING in lines[line_idx + 1]):
                next_line = lines[line_idx + 1]
                num_copies = 1
                num_copies_match = NUMBER_COPIES.search(next_line)
                if num_copies_match:
                    num_copies = int(num_copies_match.group(1))
                returns.extend(card_revealed * num_copies)
        if KW_REVEALING in line and KW_TO_THE_SUPPLY in line:
            # old style ambassador line
            returns.extend(capture_cards(line))
        if KW_GETTING in line or KW_GETS in line or KW_GET in line:
            money_match = GETTING_MONEY_RE.search(line)
            if money_match:
                turn_money += int(money_match.group(1))
        if KW_WHICH_IS_WORTH in line:
            worth_match = WHICH_IS_WORTH_RE.search(line)
            assert bool(worth_match), line
            turn_money += int(worth_match.group(1))
        if KW_FOR_MONEY in line:
            worth_match = FOR_MONEY_RE.search(line)
            assert bool(worth_match), line
            turn_money += int(worth_match.group(1))
        if u'▼' in line:
            vp_tokens += int(VP_TOKEN_RE.search(line).group('num'))
        if KW_INSTEAD in line and not KW_WISHING in line and 'Trader' in line:
            if 'buy_or_gain' in targ_obj:
                targ_list = targ_obj[targ_obj['buy_or_gain']]
                non_silver_ind = len(targ_list) - 1
                while (non_silver_ind >= 0 and
                       targ_list[non_silver_ind] == 'Silver'):
                    non_silver_ind -= 1
                # This shouldn't work when there is no non-silver, but then
                # non_silver_ind == -1 if there is no non-silver,
                # which magically pops the last item.  <3 guido.
                targ_list.pop(non_silver_ind)
            else:
                assert 'Ill-Gotten Gains' in plays, (
                    "line %s: line\n, targ_obj: %s\n context: %s" % (
                        line, str(targ_obj),
                        '\n'.join(lines[line_idx - 2: line_idx + 2])))

        now_buys_len = len(targ_obj.get(BUYS, []))
        now_gains_len = len(targ_obj.get(GAINS, []))
        if now_buys_len > orig_buys_len:
            targ_obj['buy_or_gain'] = BUYS
        if now_gains_len > orig_gains_len:
            targ_obj['buy_or_gain'] = GAINS

        assert not (now_buys_len > orig_buys_len and
                    now_gains_len > orig_gains_len), 'buys or gains mismatch'

    def _delete_if_exists(d, n):
        if n in d:
            del d[n]

    _delete_if_exists(ret, 'buy_or_gain')

    if poss:
        possessee_info = opp_turn_info[str(possessee_index)]
        for k in [GAINS, TRASHES]:
            _delete_if_exists(possessee_info, k)

        possessee_info[VP_TOKENS], vp_tokens = vp_tokens, 0
        possessee_info[RETURNS], returns = returns, []
        ret[BUYS] = []  # buys handled by possesion gain line.

    for opp in opp_turn_info.keys():
        _delete_if_exists(opp_turn_info[opp], 'buy_or_gain')
        delete_keys_with_empty_vals(opp_turn_info[opp])

        d = opp_turn_info[opp]
        for k, v in d.iteritems():
            if k==VP_TOKENS:
                d[k] = v
            else:
                d[k] = indexes(v)

    ret[BUYS] = indexes(ret[BUYS])
    ret[GAINS] = indexes(ret[GAINS])
    ret[TRASHES] = indexes(ret[TRASHES])

    ret.update({NAME: names_list[tracker.current_player()],
                PLAYS: indexes(plays) , RETURNS: indexes(returns),
                MONEY: count_money(plays) + turn_money,
                VP_TOKENS: vp_tokens, PIRATE_TOKENS: ps_tokens,
                POSSESSION: poss, OUTPOST: outpost,
                OPP: dict(opp_turn_info)})

    delete_keys_with_empty_vals(ret)
    return ret
Example #19
0
    line = log_lines.pop(0)
    supply_cards_text = line.split(', ')
    supply_cards_text[0] = supply_cards_text[0].replace('Supply cards: ','')
    supply_cards = []
    for card_name in supply_cards_text:
        try:
            card = get_card(card_name)
        except KeyError, exception:
            raise parse_common.ParsingError('%s is not a card in the supply!'
                                            % card_name)
        supply_cards.append(card.index)

    bane_match = BANE_RE.match(log_lines[0])
    if bane_match:
        try:
            bane_card = get_card(bane_match.groups()[0])
            log_lines.pop(0)
        except KeyError, exception:
            raise parse_common.ParsingError('%s is not a valid bane!'
                                            % card_name)
    return supply_cards

def parse_header(log_lines):
    """Parse the goko header. 
    
    It begins with the 'Game Setup' line and ends with the blank line before
    the first player's first turn.
    """

    # first line - header line
    line = log_lines.pop(0)
Example #20
0
def parse_deck(deck_str):
    """ Given an isotropic deck string, return a dictionary containing the
    player names

    deck_str: starts with placement and name, ends with last card in deck.
    returns dictionary containing the following fields
      name:
      vp_tokens: number of vp tokens.
      deck: Dictionary keyed card name who value is the card frequency.
      resigned: True iff this player resigned
      """
    try:
        name_vp_list, _opening, deck_contents = deck_str.split('\n')
    except ValueError as e:
        raise ParsingError('Failed right off the bat to split the deck')
    vp_tokens = 0
    #print 'vp', name_vp_list

    matched_points = POINTS_RE.search(name_vp_list)

    if matched_points:
        point_loc = matched_points.end()
        resigned, points = False, int(matched_points.group(1))
        name_points, vp_list = (name_vp_list[:point_loc],
                                name_vp_list[point_loc + 1:])
    else:
        resign_loc = name_vp_list.find('resigned')
        assert resign_loc != -1, 'could not find resign in %s' % name_vp_list
        resigned, points = True, -100
        name_points, vp_list = (name_vp_list[:resign_loc],
                                name_vp_list[resign_loc + 1:])

    last_colon_in_name_points = name_points.rfind(':')
    name, _points_or_resign = (name_points[:last_colon_in_name_points],
                               name_points[last_colon_in_name_points + 1:])

    def cleanup_name(name):
        """ Given a name and placement, get rid of the bold tags and  """
        htmlless_name = name.replace('<b>', '').replace('</b>', '')
        placement_match = PLACEMENT_RE.match(htmlless_name)
        if placement_match:
            return placement_match.group(1)
        return htmlless_name

    name = cleanup_name(name)

    for chunk in vp_list.split(','):
        diamond_loc = chunk.find(u'▼')
        if diamond_loc != -1:
            start_point_loc = max(chunk.rfind('(', 0, diamond_loc - 1),
                                  chunk.rfind(' ', 0, diamond_loc - 1))
            vp_tokens = int(chunk[start_point_loc + 1:diamond_loc - 1])

        card_list_chunks = deck_contents[deck_contents.find(']') + 1:].replace(
            ',', ' ')
        card_blobs = [
            x for x in card_list_chunks.split('</span>') if '<span' in x
        ]
        deck_comp = {}
        for card_blob in card_blobs:
            right_bracket_index = card_blob.find('>')
            card_name = card_blob[right_bracket_index + 1:]
            try:
                card = get_card(card_name)
            except KeyError as exception:
                raise ParsingError("Failed to get card. chunk: '%s', card_name: '%s', card_blob: '%s'" % \
                                       (chunk, card_name, card_blob[right_bracket_index - 10:]))
            card_quant = int(card_blob.split()[0])
            deck_comp[str(card.index)] = card_quant
    #FIXME: deck_comp is undefined if there's no vp_list
    return {
        NAME: name,
        POINTS: points,
        RESIGNED: resigned,
        DECK: deck_comp,
        VP_TOKENS: vp_tokens
    }