예제 #1
0
def cube_scars_use(cube_id):
    cube = Cube.query.get(cube_id)
    cube_wrapper = CubeWrapper(cube)

    form = UseScarForm()
    form.card_name.choices = [x.name() for x in cube_wrapper.cards()]

    if not form.validate_on_submit():
        flash('Scar use failed')
        return redirect(url_for('cube_scars', cube_id=cube_id))

    card = cube.get_card_by_name(form.card_name.data)
    scar = Scar.query.get(form.scar_id.data)

    if not card:
        flash(f'Invalid card name: {form.card_name.data}')
        return redirect(url_for('cube_scars', cube_id=cube_id))

    if not scar:
        flash(f'Invalid scar id: {form.card_id.data}')
        return redirect(url_for('cube_scars', cube_id=cube_id))

    scar.applied_timestamp = datetime.utcnow()
    scar.applied_by_id = current_user.id
    scar.applied_to_id = card.id

    db.session.add(scar)
    db.session.commit()

    flash(f'Scar applied to {card.name()}')
    return redirect(url_for('cube_scars', cube_id=cube_id))
def _make_commander_packs(cube, unused, num_packs, num_players):
    cube_wrapper = CubeWrapper(cube)
    card_breakdown = {
        'all': cube_wrapper.cards(),
        'rare': [],  # mythics get shuffled in here
        'uncommon': [],
        'common': [],
        'legendary': [],  # All the legendary creatures
    }

    distribution = [
        ('rare', 1),
        ('uncommon', 3),
        ('legendary', 2),
        ('common', 13),
        ('all', 1),  # Foil
    ]

    for card in card_breakdown['all']:
        if 'legendary creature' in card.type_line().lower():
            card_breakdown['legendary'].append(card)
        elif card.rarity() in ('rare', 'mythic'):
            card_breakdown['rare'].append(card)
        elif card.rarity() == 'uncommon':
            card_breakdown['uncommon'].append(card)
        elif card.rarity() == 'common':
            card_breakdown['common'].append(card)
        else:
            raise ValueError(f"Unknown rarity '{card.rarity()}' on '{card.name()}'")

    return _make_set_packs(card_breakdown, distribution, num_packs * num_players)
예제 #3
0
def cube_scars(cube_id):
    cube = Cube.query.get(cube_id)

    form = NewScarForm()
    form.update_as.choices = User.all_names()
    form.update_as.data = current_user.name

    rsform = RandomScarsForm()
    if rsform.validate_on_submit():
        random_scar_count = int(rsform.count.data)
        random_scars = Scar.random_scars(cube_id, random_scar_count)

    else:
        rsform.count.data = '2'
        random_scars = []

    cube_wrapper = CubeWrapper(cube)

    use_scar_form = UseScarForm()
    use_scar_form.card_name.choices = [''] + [
        x.name() for x in cube_wrapper.cards()
    ]

    return render_template(
        'cube_scars.html',
        cube=cube,
        cw=cube_wrapper,
        form=form,
        rsform=rsform,
        usform=use_scar_form,
        random_scars=random_scars,
    )
예제 #4
0
    def __init__(self, draft_id, user_id):
        draft = Draft.query.get(draft_id)
        if draft.parent_id:
            self.draft = Draft.query.get(draft.parent_id)
        else:
            self.draft = draft
        self.draft_ids = [self.draft.id
                          ] + [x.id for x in self.draft.children()]

        self.cube = self.draft.cube
        self.cube_wrapper = CubeWrapper(self.cube)

        self.user = User.query.get(user_id)

        self.seats = Seat.query.filter(
            Seat.draft_id.in_(self.draft_ids),
            Seat.user_id == self.user.id,
        ).all()

        self.deck = self._load_deck()

        self.card_set = CardSet()
        for card in self.deck.maindeck():
            self.card_set.add_card(card, maindeck=True)

        for card in self.deck.sideboard():
            self.card_set.add_card(card, sideboard=True)

        for card in self.deck.command():
            self.card_set.add_card(card, command=True)
    def cube_packs(setup: dict, user_data: list):
        # Create a separate 'more_setup' dict here and merge it into the setup dict at the end.
        # Creating it here makes it easy to see what keys are added.
        more_setup = {
            'packs': [],  # pack id to pack mapping
            'picks':
            [],  # { 'user_id': id, 'pack_id': pack_id, 'card_id': card_id }
        }

        cube = Cube.query.get(setup['cube_id'])
        wrapper = CubeWrapper(cube)
        card_data = wrapper.card_data(include_removed=False)

        num_packs = setup['num_packs']
        pack_size = setup['pack_size']
        pack_count = len(user_data) * num_packs
        card_count = pack_count * pack_size

        if len(card_data) < card_count:
            raise ValueError(
                f"Not enough cards for {num_users} users * {num_packs} packs * {pack_size} cards"
            )

        included_card_data = {}

        card_ids = [str(x) for x in card_data.keys()]
        random.shuffle(card_ids)
        for i in range(pack_count):
            start = i * pack_size
            end = start + pack_size
            user_id = user_data[i // num_packs]['id']

            pack = {
                'pack_id': i,
                'card_ids': card_ids[start:end],
                'user_id': user_id,  # User who opens pack
                'pack_num': i % num_packs,  # Order of pack opening
                'waiting_id': user_id,  # User who needs to pick from this pack
                'waiting_picks': 1,
                'picked_ids': [],
                'events': [],
                'opened': False,
            }

            more_setup['packs'].append(pack)

            for card_id in pack['card_ids']:
                included_card_data[card_id] = card_data[int(card_id)]

        setup.update(more_setup)

        return included_card_data
    def rotisserie(setup: dict, user_data: list):
        cube = Cube.query.get(setup['cube_id'])
        wrapper = CubeWrapper(cube)
        card_data = wrapper.card_data(include_removed=False)

        first_pick_id = random.choice(user_data)['id']

        setup.update({
            'card_ids': [str(x) for x in card_data.keys()],
            'waiting_id': first_pick_id,
            'picked_ids': [],
            'events': [],
        })
        return card_data
def _make_cube_packs(cube, pack_size, num_packs, num_players):
    cube_wrapper = CubeWrapper(cube)
    cards = cube_wrapper.cards()

    total_cards = pack_size * num_packs * num_players
    total_packs = num_packs * num_players

    if len(cards) < total_cards:
        raise ValueError("Not enough cards ({}) for {} packs of size {} and {} players.".format(
            len(cards), num_packs, pack_size, num_players))

    random.shuffle(cards)
    packs = []
    for i in range(total_packs):
        start = i * pack_size
        end = start + pack_size
        packs.append(cards[start:end])

    return packs  # List of list of Card ORMs
예제 #8
0
def cube_data(cube_id):
    cube = Cube.query.get(cube_id)
    data = CubeData(cube)

    return render_template(
        'cube_data.html',
        cube=cube,
        cw=CubeWrapper(cube),
        d=data,
    )
예제 #9
0
def pack_of_cards(cube_id, num_cards, random_seed):
    num_cards = int(num_cards)

    randomizer = random.Random(random_seed)
    cube = Cube.query.get(cube_id)
    cube_wrapper = CubeWrapper(cube)

    cards = cube_wrapper.cards()
    randomizer.shuffle(cards)
    cards = cards[:num_cards]

    card_data = {}
    for card in cards:
        card_data[card.id] = card.get_json()

    return render_template(
        'pack_of_cards.html',
        title=f"Pack of {num_cards} cards from {cube.name}",
        cards=cards,
        card_data=card_data,
    )
예제 #10
0
def cube_cards(cube_id):
    search_id = request.args.get('search_id')

    cube = Cube.query.get(cube_id)
    wrapper = CubeWrapper(cube, search_id)

    return render_template(
        'cube_cards.html',
        cube=cube,
        cw=wrapper,
        t=CardTable(wrapper),
        add_cards_form=AddCardsForm(),
        rare_form=CardRarityForm(),
    )
예제 #11
0
def cube_achievements(cube_id):
    form = NewAchievementForm()
    form.update_as.choices = User.all_names()
    form.update_as.data = current_user.name
    form.cube_id.data = cube_id
    form.group_fields()

    cube = Cube.query.get(cube_id)
    return render_template(
        'cube_achievements.html',
        cube=cube,
        cw=CubeWrapper(cube),
        form=form,
    )
예제 #12
0
    def __init__(self, draft_id, user):
        self.draft = Draft.query.get(draft_id)
        self.cube = self.draft.cube
        self.cube_wrapper = CubeWrapper(self.cube)

        self.seats = self.draft.seats
        self.seats.sort(key=lambda x: x.order)

        self.user = user
        self.seat = next(x for x in self.seats if x.user_id == self.user.id)
        self.pack = self.seat.waiting_pack()

        self.deck_builder = DeckBuilder(self.draft.id, self.user.id)

        self.results_dict = self._game_results_linked()
예제 #13
0
def cube_interns(cube_id):
    cube = Cube.query.get(cube_id)

    card = CubeCard.query.filter(
        CubeCard.cube_id == cube.id,
        CubeCard.latest_id == CubeCard.id,
    )
    interns = [x for x in card if 'intern of' in x.oracle_text().lower()]

    live_interns = [x for x in interns if not x.removed_by_id]
    dead_interns = [x for x in interns if x.removed_by_id]

    live_interns.sort(key=lambda x: x.timestamp, reverse=True)
    dead_interns.sort(key=lambda x: x.removed_by_timestamp, reverse=True)

    return render_template(
        'cube_interns.html',
        cube=cube,
        cw=CubeWrapper(cube),
        live_interns=live_interns,
        dead_interns=dead_interns,
    )
예제 #14
0
class CubeData(object):
    def __init__(self, cube):
        self.cube = cube
        self.cube_wrapper = CubeWrapper(self.cube)
        self.info = self._pick_info()
        self.ratios = CreatureRatios(self.cube_wrapper.card_set())

    def creature_types(self):
        types = {}

        for card in self.cube_wrapper.cards():
            for face in card.card_faces():
                if 'creature' in face['type_line'].lower():
                    subtypes = self._extract_subtypes(face['type_line'])
                    for type in subtypes:
                        types.setdefault(type, []).append(card)

        for key in types:
            types[key] = list(set(types[key]))
            types[key].sort(key=lambda x: x.name())

        types_list = list(types.items())
        types_list.sort()

        return types_list

    def first_picks(self):
        more_than_one = [x for x in self.info.values() if x.first_picks() > 1]
        counts = [(x.card.name(), x.first_picks()) for x in more_than_one]
        counts.sort(key=lambda x: (-x[1], x[0]))
        return counts

    def highest_picks(self):
        sorted_picks = [x for x in self.info.values() if len(x.picks) > 1]
        sorted_picks.sort(key=lambda x: x.average_pick())
        return sorted_picks

    def _extract_subtypes(self, type_line):
        for i in range(len(type_line)):
            if not type_line[i].isalpha() and not type_line[i].isspace():
                return type_line[i+1:].strip().split()

        return []

    def _pick_info(self):
        from app.models.cube_models import CubeCard
        from app.models.draft_models import Draft
        from app.models.draft_models import PackCard

        drafts = [
            x.id for x in Draft.query.filter(Draft.cube_id == self.cube.id).all()
            if x.complete
        ]
        picks = PackCard.query.filter(
            PackCard.draft_id.in_(drafts),
            PackCard.pick_number >= 0,
        ).all()

        pick_info = {}
        for pick in picks:
            if pick.cube_card.removed_by_timestamp:
                continue
            info = pick_info.setdefault(pick.cube_card.latest_id, CardPickInfo(pick.cube_card))
            info.picks.append(pick)

        self._maindeck_info(pick_info)

        return pick_info

    def _maindeck_info(self, pick_info):
        for deck in Deck.query.all():
            for card_id in deck.maindeck_ids.split(','):
                if not card_id:
                    continue

                card_id = int(card_id)
                if card_id in pick_info:
                    pick_info[card_id].maindecked += 1
예제 #15
0
class DeckBuilder(object):
    def __init__(self, draft_id, user_id):
        draft = Draft.query.get(draft_id)
        if draft.parent_id:
            self.draft = Draft.query.get(draft.parent_id)
        else:
            self.draft = draft
        self.draft_ids = [self.draft.id
                          ] + [x.id for x in self.draft.children()]

        self.cube = self.draft.cube
        self.cube_wrapper = CubeWrapper(self.cube)

        self.user = User.query.get(user_id)

        self.seats = Seat.query.filter(
            Seat.draft_id.in_(self.draft_ids),
            Seat.user_id == self.user.id,
        ).all()

        self.deck = self._load_deck()

        self.card_set = CardSet()
        for card in self.deck.maindeck():
            self.card_set.add_card(card, maindeck=True)

        for card in self.deck.sideboard():
            self.card_set.add_card(card, sideboard=True)

        for card in self.deck.command():
            self.card_set.add_card(card, command=True)

    def all_cards(self):
        cards = []

        drafts = Draft.query.filter(Draft.id.in_(self.draft_ids)).all()
        for draft in drafts:
            cards += self.cube_wrapper.cards(include_removed=True)

        return list(set(cards))

    def basics(self, name):
        if not self.deck.basic_lands:
            return '0'

        for elem in self.deck.basic_lands.split(','):
            tokens = elem.split()
            if len(tokens) == 2 and tokens[1] == name:
                return tokens[0]
        return '0'

    def card_data(self):
        data = {}
        for card in self.card_set:
            data[card.id] = card.get_json()

        return data

    def deck_list(self, legacy_names=False):
        """
        Return a decklist formatted to be used by Cockatrice and other systems.
        """
        cards = []

        for card in self.deck.maindeck():
            if legacy_names:
                cards.append(card.cockatrice_name())
            else:
                cards.append(card.name())

        for basic in [
                x.strip() for x in self.deck.basic_lands.split(',')
                if x.strip()
        ]:
            if legacy_names:
                cards.append(basic + "'")
            else:
                cards.append(basic)

        cards.append('\u00a0')  # Non-breaking space

        for card in self.deck.sideboard() + self.deck.command():
            if legacy_names:
                cards.append(card.cockatrice_name())
            else:
                cards.append(card.name())

        return cards

    def is_legacy(self):
        return self.draft.cube.style_a == 'legacy'

    def _load_deck(self):
        existing_deck = self.draft.deck_for(self.user.id)

        if existing_deck:
            return existing_deck
        else:
            return self._new_deck()

    def _new_deck(self):
        deck = Deck()
        deck.user_id = self.user.id
        deck.name = f"{self.user.name}'s {self.draft.name} Deck"

        maindeck = []
        sideboard = []
        for card in self._picked_cards():
            if card.sideboard:
                sideboard.append(card.cube_card)
            else:
                maindeck.append(card.cube_card)

        deck.set_maindeck(maindeck)
        deck.set_sideboard(sideboard)

        db.session.add(deck)
        db.session.commit()

        # Create a link between this deck and the draft
        link = DeckDraftLink()
        link.deck_id = deck.id
        link.draft_id = self.draft.id
        db.session.add(link)
        db.session.commit()

        return deck

    def _picked_cards(self):
        picked_cards = []
        for seat in self.seats:
            picked_cards += [x.cube_card for x in seat.picks]
        return picked_cards
예제 #16
0
def _make_standard_packs(cube, unused, num_packs, num_players):
    cube_wrapper = CubeWrapper(cube)

    card_breakdown = {
        'all': cube_wrapper.cards(),
        'rare': [],  # mythics get shuffled in here
        'uncommon': [],
        'common': [],
    }

    distribution = [
        ('rare', 1),
        ('uncommon', 3),
        ('common', 10),
    ]

    separate_double_faced = False

    # These sets replaced one common slot with a double-faced card of any rarity.
    if cube.set_code.lower() in ('isd', 'dka'):
        separate_double_faced = True
        card_breakdown['double-faced'] = []
        distribution = [
            ('rare', 1),
            ('uncommon', 3),
            ('double-faced', 1),
            ('common', 9),
        ]

    if cube.set_code.lower() == 'khm':
        distribution.append(('snow-land', 1))
        card_breakdown['snow-land'] = []


    for card in card_breakdown['all']:
        if cube.set_code.lower() == 'khm' and 'snow land' in card.type_line().lower():
            # One pack in six should have a snow dual.
            # Since there are ten snow duals, have 10 of each basic to make the ratios right.
            if 'basic' in card.type_line().lower():
                card_breakdown['snow-land'] += [card] * 10
            else:
                card_breakdown['snow-land'].append(card)

        elif separate_double_faced and '//' in card.name():
            # Need to get the distribution right for rarity.
            if card.rarity() == 'mythic':
                card_breakdown['double-faced'].append(card)
            elif card.rarity() == 'rare':
                card_breakdown['double-faced'] += [card] * 7
            elif card.rarity() == 'uncommon':
                card_breakdown['double-faced'] += [card] * 24
            elif card.rarity() == 'common':
                card_breakdown['double-faced'] += [card] * 88
            else:
                raise ValueError(f"Unknown rarity '{card.rarity()}' on '{card.name()}'")
        elif card.rarity() == 'mythic':
            card_breakdown['rare'].append(card)
        elif card.rarity() == 'rare':
            card_breakdown['rare'].append(card)
            card_breakdown['rare'].append(card)  # Mythics are twice as rare as regular rares
        elif card.rarity() == 'uncommon':
            card_breakdown['uncommon'].append(card)
        elif card.rarity() == 'common':
            card_breakdown['common'].append(card)
        else:
            raise ValueError(f"Unknown rarity '{card.rarity()}' on '{card.name()}'")

    return _make_set_packs(card_breakdown, distribution, num_packs * num_players)
    def _make_pack_slot_pools(cube_id):
        cube = Cube.query.get(cube_id)
        wrapper = CubeWrapper(cube)
        set_code = cube.set_code.lower() if cube.set_code else 'other'

        pools = {
            'all': wrapper.cards(),
            'rare': [],
            'uncommon': [],
            'common': [],
            'basic-land': RoundBuilder._basic_land_pool(),
        }

        distribution = [
            ('rare', 1),
            ('uncommon', 3),
            ('common', 10),
            ('basic-land', 1),
        ]

        # Special distributions/pools for some sets.

        if set_code == 'khm':
            pools['snow-land'] = []

        elif set_code in ('isd', 'dka'):
            pools['double-faced'] = []
            distribution = [
                ('rare', 1),
                ('double-faced', 1),
                ('uncommon', 3),
                ('common', 9),
            ]

        # Build pools

        for card in pools['all']:
            if set_code == 'khm' and 'snow land' in card.type_line().lower():
                # One pack in six should have a snow dual.
                # Since there are ten snow duals, have 10 of each basic to make the ratios right.
                if 'basic' in card.type_line().lower():
                    pools['snow-land'] += [card] * 10
                else:
                    pools['snow-land'].append(card)

            elif 'double-faced' in pools and '//' in card.name():
                # Need to get the distribution right for rarity.
                # There is 1 of each mythic for every 2 of each rare
                # There is 1 of each rare for every 3 of each uncommon
                # There is 1 of each rare for every 11 of each common
                if card.rarity() == 'mythic':
                    pools['double-faced'].append(card)
                elif card.rarity() == 'rare':
                    pools['double-faced'] += [card] * 2
                elif card.rarity() == 'uncommon':
                    pools['double-faced'] += [card] * 6
                elif card.rarity() == 'common':
                    pools['double-faced'] += [card] * 22
                else:
                    raise ValueError(
                        f"Unknown rarity '{card.rarity()}' on '{card.name()}'")
            elif card.rarity() == 'mythic':
                pools['rare'].append(card)
            elif card.rarity() == 'rare':
                pools['rare'].append(card)
                pools['rare'].append(
                    card)  # Mythics are twice as rare as regular rares
            elif card.rarity() == 'uncommon':
                pools['uncommon'].append(card)
            elif card.rarity() == 'common':
                pools['common'].append(card)
            else:
                raise ValueError(
                    f"Unknown rarity '{card.rarity()}' on '{card.name()}'")

        return pools, distribution
예제 #18
0
 def __init__(self, cube):
     self.cube = cube
     self.cube_wrapper = CubeWrapper(self.cube)
     self.info = self._pick_info()
     self.ratios = CreatureRatios(self.cube_wrapper.card_set())