class Card:
    ranks = '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'
    rank_map = {name: rank for rank, name in enumerate(ranks, 1)}

    def __init__(self, card):
        self._card = card

        if card != 'Joker':
            rank, suit = card[:-1], card[-1:]
            self.rank = Card.rank_map[rank]
            self.suit = suit
        else:
            self.rank = -1
            self.suit = ''

    @property
    def is_joker(self):
        return self._card == 'Joker'

    def __repr__(self):
        return self._card


def is_straight(cards, min_cards=5):
    if len(cards) < min_cards:
        return False

    ranks = sorted(x.rank for x in cards if not x.is_joker)
    jokers = len(cards) - len(ranks)

    for i, rank in enumerate(ranks[:-1]):
        difference = ranks[i + 1] - rank

        if difference == 1:
            continue

        # fill the gap between the ranks with jokers
        if jokers >= difference - 1 > 0:
            jokers -= difference - 1
            continue

        return False

    return True


tests = (
    (False, ),
    (False, 'A♣', 'A♣', 'A♠', '2♦', 'A♥'),
    (False, 'K♣', 'K♣', 'Q♠', '10♦', 'A♥'),
    (False, '9♣', 'K♣', 'Q♠', 'J♦', 'A♥'),
    (False, 'K♣', 'Q♠', 'J♦', '10♥'),
    (False, 'Joker', 'Joker', 'Joker', 'Joker'),
    (False, '10♣', 'A♣', 'Joker', '9♦', '8♥'),
    (False, 'Q♣', 'Q♣', 'Joker', '10♦', 'A♥'),
    (True,  'A♣', 'K♣', 'Q♠', 'J♦', '10♥'),
    (True,  '10♣', 'K♣', 'Q♠', 'J♦', 'A♥'),
    (True,  '10♣', 'K♣', 'Joker', 'J♦', 'A♥'),
    (True,  '10♣', 'Joker', 'Joker', '9♦', '8♥'),
    (True,  'Joker', 'Joker', 'Joker', 'Joker', '9♦'),
    (True,  'Joker', 'Joker', 'Joker', 'Joker', 'Joker'),
)

for expected, *cards in tests:
    cards = [Card(card) for card in cards]
    assert expected == is_straight(cards), (cards, expected)