def sample_win_probability_dumb(board, value_to_beat, deck, left_to_deal, nsamples=100): nwins = 0 cards = deck.cards copied_deck = Deck() for _ in xrange(nsamples): shuffle(cards) copied_deck.cards = list(cards) won = False decided = False best_value = value_to_beat chosen_value = 10**10 for x in range(left_to_deal): hand = copied_deck.draw(2) value = evaluator.evaluate(board, hand) if value < value_to_beat and not decided: # have to decide whether to stay! win_prob = chance_to_win_given_choice(board, value, deck, left_to_deal - x - 1) if win_prob > 0.5: chosen_value = value decided = True best_value = min(best_value, value) if chosen_value < best_value: nwins += 1 return nwins * 1.0 / nsamples
def possibility_of_getting_burnt(board, chosen_value, deck, left_to_deal, nsamples=100): # the only way that keeping the hand with a <50% chance of winning # is the correct move is if there is at least some possibility that # there will be *two* hands that beat you, and moreover they come in # the wrong order if left_to_deal <= 1: # you IDIOT, of course keep your hand return 0 nburns = 0 cards = deck.cards copied_deck = Deck() for _ in xrange(nsamples): shuffle(cards) copied_deck.cards = list(cards) got_beat = False value_to_beat = -1 for x in range(left_to_deal): hand = copied_deck.draw(2) value = evaluator.evaluate(board, hand) if got_beat and value < value_to_beat: nburns += 1 break if value < chosen_value: got_beat = True value_to_beat = value return nburns * 1.0 / nsamples
def sample_win_probability(board, value_to_beat, deck, left_to_deal, nsamples=50): pwin = 0. cards = deck.cards copied_deck = Deck() for _ in xrange(nsamples): shuffle(cards) copied_deck.cards = list(cards) new_hand = copied_deck.draw(2) value = evaluator.evaluate(board, new_hand) if value > value_to_beat: # the new hand is worse, so no decision to be made if left_to_deal > 1: # just burn the cards and keep going pwin += sample_win_probability(board, value_to_beat, copied_deck, left_to_deal - 1) elif left_to_deal == 1: # this was our last chance, we lost pwin += 0 else: if left_to_deal == 1: # this was our last hand. We won! pwin += 1 else: # we have a choice. What do we do?? prob_if_stayed, prob_burn = chance_to_win_given_choice( board, value, copied_deck, left_to_deal - 1, return_burns=True) # we have the inequality # P(there is a better hand) - P(you get "burnt") # < P(win if you pass) < P(there is a better hand) # also, # P(there is a better hand) = 1 - P(win if you stay) # If P(win if you pass) < P(win if you stay) then you should stay # and if P(win if you pass) > P(win if you stay) then you should continue if prob_if_stayed > 0.5: # definitely should stay pwin += prob_if_stayed continue if prob_burn <= 0.1: # if burns are pretty rare, then let's just say that # the win probability is well approximated by the # "dumb" strategy. prob_if_passed = sample_win_probability_dumb( board, value, copied_deck, left_to_deal - 1) else: prob_if_passed = sample_win_probability( board, value, copied_deck, left_to_deal - 1) pwin += max(prob_if_stayed, prob_if_passed) return pwin * 1. / nsamples
def chance_to_win_given_choice(board, chosen_value, deck, left_to_deal, nsamples=100, return_burns=False): if left_to_deal == 0: if return_burns: return (1., 0.) return 1. nwins = 0 nburns = 0 cards = deck.cards copied_deck = Deck() for _ in xrange(nsamples): shuffle(cards) copied_deck.cards = list(cards) won = True burnt = False value_to_beat = -1 for x in range(left_to_deal): hand = copied_deck.draw(2) value = evaluator.evaluate(board, hand) if not won and value < value_to_beat: burnt = True break if value < chosen_value: won = False value_to_beat = value if won: nwins += 1 if burnt: nburns += 1 if return_burns: return (nwins * 1.0 / nsamples, nburns * 1.0 / nsamples) return nwins * 1.0 / nsamples
def set_deck(hand, board): deck = Deck() deck.cards = list(set(deck.cards) - set(hand) - set(board)) return deck
def generate_odds(): card_ints = [i for i in range(13)] pair_combos = combinations_with_replacement(card_ints, 2) eval = Evaluator() pair_scores = np.zeros(shape=(13, 13)) pair_suits = [8, 8] for x in pair_combos: deck = Deck() deck_match_idxs = [] hero_cards = [None, None] if x[0] == x[1]: continue # Find cards in deck for deck_idx, card in enumerate(deck.cards): if x[0] == Card.get_rank_int(card) and pair_suits[0] == Card.get_suit_int(card): hero_cards[0] = card deck_match_idxs.append(deck_idx) if x[1] == Card.get_rank_int(card) and pair_suits[1] == Card.get_suit_int(card): hero_cards[1] = card deck_match_idxs.append(deck_idx) # Remove hero cards from deck deck.cards = [i for idx, i in enumerate(deck.cards) if idx not in deck_match_idxs] # Repeat x times num_wins = 0 num_losses = 0 while num_wins + num_losses < 10000: # Draw villan cards villan_cards = deck.draw(2) # Draw five card board board = deck.draw(5) # Find winner hero_rank = eval.evaluate(hero_cards, board) villan_rank = eval.evaluate(villan_cards, board) if hero_rank < villan_rank: num_wins += 1 elif hero_rank > villan_rank: num_losses += 1 else: None # Put villan and board cards back into deck deck.cards.extend(villan_cards) deck.cards.extend(board) # Shuffle deck for next draw shuffle(deck.cards) pair_scores[x[0], x[1]] = num_wins / (num_wins + num_losses) pair_scores[x[1], x[0]] = num_wins / (num_wins + num_losses) np.savetxt('./suited_pair_scores.csv', pair_scores, delimiter=',', fmt='%5f') print(pair_scores)