Enable Javascript in your browser and then refresh this page, for a much enhanced experience.
Second solution in Clear category for Magic with 5 cards by mortonfox
RANKS = tuple('A 2 3 4 5 6 7 8 9 10 J Q K'.split())
SUITS = tuple('♣♦♥♠')
RANKTABLE = {RANKS[i]: i for i in range(len(RANKS))}
SUITTABLE = {SUITS[i]: i for i in range(len(SUITS))}
def suit(card):
return card.split()[1]
def rank(card):
return card.split()[0]
def card_to_val(card):
return RANKTABLE[rank(card)] * 4 + SUITTABLE[suit(card)]
def sorted_cards(cards):
return sorted(cards, key=card_to_val)
def sorted_by_suit(cards):
return sorted(cards, key=lambda card: SUITTABLE[suit(card)])
def bot(*cards, n=1):
"""Determine four cards the bot has to say to the magician."""
cards = sorted_by_suit(cards)
# Find two cards of the same suit.
same_suit_idx = [i for i, (card1, card2) in enumerate(zip(cards, cards[1:])) if suit(card1) == suit(card2)][0]
same_suit = cards[same_suit_idx:same_suit_idx+2]
del cards[same_suit_idx:same_suit_idx+2]
rank_a = RANKTABLE[rank(same_suit[0])]
rank_b = RANKTABLE[rank(same_suit[1])]
dist_fwd = (rank_b - rank_a) % 13
# Figure out the delta and which of the same-suit cards we say.
delta, say = (dist_fwd, same_suit[0]) if dist_fwd < 13 - dist_fwd else (13 - dist_fwd, same_suit[1])
cards = sorted_cards(cards)
# Which of the other 3 cards go first?
first_card = cards.pop((6 - delta) // 2)
# Should we reverse the remaining 2 cards?
if delta % 2 == 0:
cards = list(reversed(cards))
cards.insert(0, first_card)
# Insert the say card.
cards.insert((n - 1) % 4, say)
return cards
def magician(*cards, n=1):
"""Determine the fifth card with only four cards."""
cards = list(cards)
# Which card is the say card?
say = cards.pop((n - 1) % 4)
# Which card from the sorted list was in the first position?
first_card_idx = sorted_cards(cards).index(cards[0])
# Figure out the delta.
delta_is_even = card_to_val(cards[1]) > card_to_val(cards[2])
delta = int(delta_is_even) + 5 - 2 * first_card_idx
hide_suit = suit(say)
hide_rank = RANKS[(RANKTABLE[rank(say)] + delta) % 13]
return f'{hide_rank} {hide_suit}'
if __name__ == '__main__':
assert list(bot('A ♥', '3 ♦', 'K ♠', 'Q ♣', 'J ♦')) == ['J ♦', 'A ♥', 'Q ♣', 'K ♠']
assert magician('J ♦', 'A ♥', 'Q ♣', 'K ♠') == '3 ♦'
assert list(bot('10 ♦', 'J ♣', 'Q ♠', 'K ♥', '7 ♦', n=2)) == ['Q ♠', '7 ♦', 'J ♣', 'K ♥']
assert magician('Q ♠', '7 ♦', 'J ♣', 'K ♥', n=2) == '10 ♦'
Nov. 29, 2019
Comments: