Example #1
0
 def test_create_afei_two_folders_raise(self):
     """ Test _create_afei for a raise against two players"""
     # raise from 10 to 30 on an original pot of 10
     # unprofitable bluff
     fea = FoldEquityAccumulator(gameid=0,
                                 order=0,
                                 street=RIVER,
                                 board=[],
                                 bettor=0,
                                 range_action=None,
                                 raise_total=30,
                                 pot_before_bet=20,
                                 bet_cost=30,
                                 pot_if_called=70,
                                 potential_folders=[])
     fold_range = HandRange("KK")
     nonfold_range = HandRange("AA")
     fea.folds.append((1, fold_range, nonfold_range))  # folds 2/3
     fold_range = HandRange("QQ")
     nonfold_range = HandRange("KK+")
     fea.folds.append((1, fold_range, nonfold_range))  # folds 1/4
     afei = fea._create_afei(combo=Card.many_from_text("AsQh"), is_agg=True)
     self.assertAlmostEqual(afei.fold_ratio, 1.0 / 6.0)
     self.assertAlmostEqual(afei.immediate_result, 1.0 / 6.0 * 20.0 +
                            (5.0 / 6.0) * (-30))  # -21.66...
     self.assertAlmostEqual(afei.semibluff_ev, None)
     self.assertAlmostEqual(afei.semibluff_equity, None)
Example #2
0
 def test_create_afei_two_fodlers_reraise(self):
     """ Test _create_afei for a reraise against two players"""
     # raise from 30 to 50 on an original pot of 10
     # profitable bluff
     fea = FoldEquityAccumulator(
         gameid=0,
         order=0,
         street=RIVER,
         board=[],
         bettor=0,
         range_action=None,
         raise_total=50,
         pot_before_bet=50,
         bet_cost=50,
         pot_if_called=120,  # assumes called by the raiser, not the bettor
         potential_folders=[])
     fold_range = HandRange("KK")
     nonfold_range = HandRange("AA")
     fea.folds.append((1, fold_range, nonfold_range))  # folds 2/3
     fold_range = HandRange("KK-JJ")
     nonfold_range = HandRange("AA")
     fea.folds.append((1, fold_range, nonfold_range))  # folds 5/6
     afei = fea._create_afei(combo=Card.many_from_text("AsQh"), is_agg=True)
     self.assertAlmostEqual(afei.fold_ratio, 10.0 / 18.0)
     self.assertAlmostEqual(afei.immediate_result, 10.0 / 18.0 * 50.0 +
                            8.0 / 18.0 * (-50.0))  # 5.55...
     self.assertAlmostEqual(afei.semibluff_ev, None)
     self.assertAlmostEqual(afei.semibluff_equity, None)
Example #3
0
    def __init__(self,
                 fold_range=None, passive_range=None, aggressive_range=None,
                 raise_total=None,
                 fold_raw=None, passive_raw=None, aggressive_raw=None):
        """
        fold_range is the part of their range they fold here
        passive_range is the part of their range they check or call here
        aggressive_range is the part of their range the bet or raise here
        """
        if (fold_range is not None and fold_raw is not None) or  \
            (passive_range is not None and passive_raw is not None) or  \
            (aggressive_range is not None and aggressive_raw is not None):
            raise ValueError("Specified range and raw")
        if (fold_range is None and fold_raw is None) or  \
            (passive_range is None and passive_raw is None) or  \
            (aggressive_range is None and aggressive_raw is None):
            raise ValueError("Specified neither range or raw")
        if raise_total is None:
            raise ValueError("No raise total")

        self.fold_range = fold_range  \
            if isinstance(fold_range, HandRange)  \
            else HandRange(fold_raw)
        self.passive_range = passive_range  \
            if isinstance(passive_range, HandRange)  \
            else HandRange(passive_raw)
        self.aggressive_range = aggressive_range  \
            if isinstance(aggressive_range, HandRange)  \
            else HandRange(aggressive_raw)
        self.raise_total = raise_total
Example #4
0
 def test_create_afei_two_folders_bet(self):
     """ Test _create_afei for a bet against two players"""
     # bet 10 on a pot of 10
     # profitable bluff
     fea = FoldEquityAccumulator(gameid=0,
                                 order=0,
                                 street=RIVER,
                                 board=[],
                                 bettor=0,
                                 range_action=None,
                                 raise_total=10,
                                 pot_before_bet=10,
                                 bet_cost=10,
                                 pot_if_called=30,
                                 potential_folders=[])
     fold_range = HandRange("KK")
     nonfold_range = HandRange("AA")
     fea.folds.append((1, fold_range, nonfold_range))
     fold_range = HandRange("KK")
     nonfold_range = HandRange("AA")
     fea.folds.append((1, fold_range, nonfold_range))
     afei = fea._create_afei(combo=Card.many_from_text("AsQh"), is_agg=True)
     self.assertAlmostEqual(afei.fold_ratio, 4.0 / 9.0)
     self.assertAlmostEqual(afei.immediate_result,
                            4.0 / 9.0 * 10.0 + (5.0 / 9.0) * (-10))
     self.assertEqual(afei.semibluff_ev, None)
     self.assertEqual(afei.semibluff_equity, None)
Example #5
0
 def re_range(self, branch):
     """
     Assign new range to rgp, and redeal their hand
     """
     self.rgp.range_raw = weighted_options_to_description(branch.options)
     rgp_range = HandRange(self.rgp.range_raw)
     self.rgp.cards_dealt = rgp_range.generate_hand(self.game.board)
     logging.debug("new range for userid %d, gameid %d, new range %r, " +
                   "new cards_dealt %r", self.rgp.userid, self.rgp.gameid,
                   self.rgp.range_raw, self.rgp.cards_dealt)
Example #6
0
def safe_hand_range_form(field_name, fallback):
    """
    Pull a HandRange object from request form field <field_name>.

    If there is a problem, return HandRange(fallback).
    """
    value = request.form.get(field_name, fallback, type=str)
    hand_range = HandRange(value, is_strict=False)
    if not hand_range.is_valid():
        hand_range = HandRange(fallback)
    return hand_range
Example #7
0
def safe_hand_range(arg_name, fallback):
    """
    Pull a HandRange object from request arg <arg_name>.

    If there is a problem, return HandRange(fallback).
    """
    value = request.args.get(arg_name, fallback, type=str)
    hand_range = HandRange(value, is_strict=False)
    if not hand_range.is_valid():
        hand_range = HandRange(fallback)
    return hand_range
Example #8
0
def safe_hand_range_form(field_name, fallback):
    """
    Pull a HandRange object from request form field <field_name>.

    If there is a problem, return HandRange(fallback).
    """
    value = request.form.get(field_name, fallback, type=str)
    hand_range = HandRange(value, is_strict=False)
    if not hand_range.is_valid():
        hand_range = HandRange(fallback)
    return hand_range
Example #9
0
def safe_hand_range(arg_name, fallback):
    """
    Pull a HandRange object from request arg <arg_name>.

    If there is a problem, return HandRange(fallback).
    """
    value = request.args.get(arg_name, fallback, type=str)
    hand_range = HandRange(value, is_strict=False)
    if not hand_range.is_valid():
        hand_range = HandRange(fallback)
    return hand_range
Example #10
0
 def folder(self, ghra):
     """
     ghra is a GameHistoryRangeAction, who we consider to be a folder.
     
     Returns True if this fea is complete.
     """
     logging.debug("gameid %d, FEA %d, adding folder: userid %d",
                   self.gameid, self.order, ghra.userid)
     self.potential_folders.remove(ghra.userid)
     fold_range = HandRange(ghra.fold_range)
     pas = HandRange(ghra.passive_range)
     agg = HandRange(ghra.aggressive_range)
     nonfold_range = pas.add(agg, self.board)
     self.folds.append((ghra.userid, fold_range, nonfold_range))
     return len(self.potential_folders) == 0
Example #11
0
    def folder(self, ghra):
        """
        ghra is a GameHistoryRangeAction, who we consider to be a folder.

        Returns True if this fea is complete.
        """
        logging.debug("gameid %d, FEA %d, adding folder: userid %d",
                      self.gameid, self.order, ghra.userid)
        self.potential_folders.remove(ghra.userid)
        fold_range = HandRange(ghra.fold_range)
        pas = HandRange(ghra.passive_range)
        agg = HandRange(ghra.aggressive_range)
        nonfold_range = pas.add(agg, self.board)
        self.folds.append((ghra.userid, fold_range, nonfold_range))
        return len(self.potential_folders) == 0
Example #12
0
def _action_summary_to_vars(range_action, action_result, action_result_index,
                            user_range, index):
    """
    Summarise an action result and user range in the context of the most recent
    range action.
    """
    new_total = len(HandRange(user_range.range_raw).  \
        generate_options_unweighted())
    fol = pas = agg = NOTHING
    if action_result.action_result.is_fold:
        original = fol = range_action.range_action.fold_range.description
    elif action_result.action_result.is_passive:
        original = pas = range_action.range_action.passive_range.description
    else:
        original = agg = range_action.range_action.aggressive_range.description
    # NOTE: some of this is necessarily common with RANGE_ACTION
    return {"screenname": user_range.user.screenname,
            "action_result": action_result.action_result,
            "action_result_index": action_result_index,
            "percent": 100.0 * new_total / len(SET_ANYTHING_OPTIONS),
            "combos": new_total,
            "is_check": range_action.is_check,
            "is_raise": range_action.is_raise,
            "original": original,
            "fold": fol,
            "passive": pas,
            "aggressive": agg,
            "index": index}
Example #13
0
def rank_class(row, col, color_maker, board):
    """
    Give the appropriate class for this rank combo
    """
    txt = rank_text(row, col)
    options = HandRange(txt).generate_options_unweighted(board)
    return color_maker.get_color(options)
Example #14
0
 def finalise(self, session):
     """
     Assuming complete, return an AnalysisFoldEquity
     """
     logging.debug("gameid %d, FEA %d, calculating...", self.gameid,
                   self.order)
     assert len(self.potential_folders) == 0
     afe = self._create_afe()
     session.add(afe)
     for combo in HandRange(self.range_action.aggressive_range)  \
             .generate_options_unweighted(self.board):
         afei = self._create_afei(combo, is_agg=True)
         session.add(afei)
     for combo in HandRange(self.range_action.passive_range)  \
             .generate_options_unweighted(self.board):
         afei = self._create_afei(combo, is_pas=True)
         session.add(afei)
     for combo in HandRange(self.range_action.fold_range)  \
             .generate_options_unweighted(self.board):
         afei = self._create_afei(combo, is_fol=True)
         session.add(afei)
     logging.debug("gameid %d, FEA %d, finalised", self.gameid, self.order)
     return afe
Example #15
0
 def test_create_afei_one_folder_raise(self):
     """ Test _create_afei for a raise against one player"""
     # raise from 10 to 30 on an original pot of 10
     # profitable bluff
     fea = FoldEquityAccumulator(gameid=0,
                                 order=0,
                                 street=PREFLOP,
                                 board=[],
                                 bettor=0,
                                 range_action=None,
                                 raise_total=30,
                                 pot_before_bet=20,
                                 bet_cost=30,
                                 pot_if_called=70,
                                 potential_folders=[])
     fold_range = HandRange("KK-JJ")
     nonfold_range = HandRange("AA")
     fea.folds.append((1, fold_range, nonfold_range))
     afei = fea._create_afei(combo=Card.many_from_text("KsQh"), is_agg=True)
     self.assertAlmostEqual(afei.fold_ratio, 2.0 / 3.0)
     self.assertAlmostEqual(afei.immediate_result, 2.0 / 3.0 * 20.0 +
                            (1.0 / 3.0) * (-30.0))  # 3.33...
     self.assertAlmostEqual(afei.semibluff_ev, -10.0)
     self.assertAlmostEqual(afei.semibluff_equity, -10.0 / 70.0)
Example #16
0
 def test_create_afei_one_folder_reraise(self):
     """ Test _create_afei for a reraise against one player"""
     # raise from 30 to 50 on an original pot of 10
     # unprofitable bluff
     fea = FoldEquityAccumulator(gameid=0,
                                 order=0,
                                 street=PREFLOP,
                                 board=[],
                                 bettor=0,
                                 range_action=None,
                                 raise_total=50,
                                 pot_before_bet=50,
                                 bet_cost=40,
                                 pot_if_called=110,
                                 potential_folders=[])
     fold_range = HandRange("QQ")
     nonfold_range = HandRange("AA-KK")
     fea.folds.append((1, fold_range, nonfold_range))
     afei = fea._create_afei(combo=Card.many_from_text("KsQh"), is_agg=True)
     self.assertAlmostEqual(afei.fold_ratio, 1.0 / 4.0)
     self.assertAlmostEqual(afei.immediate_result, 1.0 / 4.0 * 50.0 +
                            (3.0 / 4.0) * (-40.0))  # -17.5
     self.assertAlmostEqual(afei.semibluff_ev, 4.0 / 3.0 * 17.5)
     self.assertAlmostEqual(afei.semibluff_equity, 4.0 / 3.0 * 17.5 / 110.0)
Example #17
0
def rank_hover(row, col, color_maker, board, is_raised, is_can_check):
    """
    Hover text for this rank combo.

    Something like "calling As8s, Ah8h; folding Ad8d".
    """
    txt = rank_text(row, col)
    options = HandRange(txt).generate_options_unweighted(board)
    inputs = [("unassigned", color_maker.opt_una),
              ("folding", color_maker.opt_fol),
              ("checking" if is_can_check else "calling", color_maker.opt_pas),
              ("raising" if is_raised else "betting", color_maker.opt_agg)]
    return " -- ".join([
        rank_hover_part(item[0], item[1].intersection(options))
        for item in inputs if item[1].intersection(options)
    ])
Example #18
0
def get_selected_options(original, board):
    """
    Get a list of options selected in the current range editor submission
    """
    options = set()
    for row in range(13):
        for col in range(13):
            desc = rank_text(row, col)
            field = "sel_" + desc
            is_sel = request.form.get(field, "false") == "true"
            if is_sel:
                new = set(HandRange(desc).generate_options_unweighted(board))
                new.intersection(original)
                options.update(
                    [option for option in new if is_suit_selected(option)])
    return options
Example #19
0
 def test_range_contains_hand(self):
     """
     Test range_contains_hand
     """
     from rvr.poker import cards
     range_ = HandRange("AA(5),KK")
     hands_in = [[
         Card(cards.ACE, cards.SPADES),
         Card(cards.ACE, cards.HEARTS)
     ], [Card(cards.KING, cards.CLUBS),
         Card(cards.KING, cards.DIAMONDS)]]
     hands_out = [[
         Card(cards.ACE, cards.SPADES),
         Card(cards.KING, cards.HEARTS)
     ], [Card(cards.DEUCE, cards.CLUBS),
         Card(cards.DEUCE, cards.DIAMONDS)]]
     for hand_in in hands_in:
         self.assertTrue(range_contains_hand(range_, hand_in))
     for hand_out in hands_out:
         self.assertFalse(range_contains_hand(range_, hand_out))
Example #20
0
def get_template_args(args):
    updated_args = {}
    updated_args['images'] = card_names(board_raw)
    board = safe_board_form('board')
    opt_ori = rng_original.generate_options_unweighted(board)
    opt_fol = rng_fold.generate_options_unweighted(board)
    opt_pas = rng_passive.generate_options_unweighted(board)
    opt_agg = rng_aggressive.generate_options_unweighted(board)
    opt_una = list(set(opt_ori) - set(opt_fol) - set(opt_pas) - set(opt_agg))
    updated_args['rng_unassigned'] = HandRange(
        unweighted_options_to_description(opt_una))
    color_maker = ColorMaker(opt_ori=opt_ori,
                             opt_una=opt_una,
                             opt_fol=opt_fol,
                             opt_pas=opt_pas,
                             opt_agg=opt_agg)
    if len(opt_ori) != 0:
        pct_unassigned = 100.0 * len(opt_una) / len(opt_ori)
        pct_fold = 100.0 * len(opt_fol) / len(opt_ori)
        pct_passive = 100.0 * len(opt_pas) / len(opt_ori)
        pct_aggressive = 100.0 * len(opt_agg) / len(opt_ori)
    else:
        pct_unassigned = pct_fold = pct_passive = pct_aggressive = 0.0
    updated_args['rank_table'] = make_rank_table(color_maker,
                                                 board,
                                                 can_check=can_check,
                                                 is_raised=args['raised'])
    updated_args['suited_table'] = make_suited_table()
    updated_args['pair_table'] = make_pair_table()
    updated_args['offsuit_table'] = make_offsuit_table()
    updated_args['hidden_fields'] = [
        ("raised", args['raised']), ("can_check", args['can_check']),
        ("can_raise", args['can_raise']), ("min_raise", args['min_raise']),
        ("max_raise", args['max_raise']), ("board", args['board_raw']),
        ("rng_original", args['rng_original'].description),
        ("rng_unassigned", args['rng_unassigned'].description),
        ("rng_fold", args['rng_fold'].description),
        ("rng_passive", args['rng_passive'].description),
        ("rng_aggressive", args['rng_aggressive'].description)
    ]
Example #21
0
def re_deal(range_action, cards_dealt, dealt_key, board, can_fold, can_call):
    """
    This function is for when we're not letting them fold (sometimes not even
    call).
    
    We reassign their hand so that it's not a fold (or call). If possible.
    Changes cards_dealt[dealt_key] to a new hand from one of the other ranges
    (unless they're folding 100%, of course).
    
    Returns fold ratio, passive ratio, aggressive ratio.
    
    In the case of can_fold and can_call, we calculate these ratios but don't
    re_deal.
    """
    # pylint:disable=R0913,R0914
    # Choose between passive and aggressive probabilistically
    # But do this by re-dealing, to account for card removal effects (other
    # hands, and the board)
    # Note that in a range vs. range situation, it's VERY HARD to determine the
    # probability that a player will raise cf. calling. But very luckily, we
    # can work around that, by using the fact that all other players are
    # currently dealt cards with a probability appropriate to their ranges, so
    # when we use their current cards as dead cards, we achieve the
    # probabilities we need here, without knowing exactly what those
    # probabilities are. (But no, I haven't proven this mathematically.)
    dead_cards = [card for card in board if card is not None]
    dead_cards.extend(concatenate([v for k, v in cards_dealt.iteritems()
                                   if k is not dealt_key]))
    fold_options = range_action.fold_range.generate_options(dead_cards)
    passive_options = range_action.passive_range.generate_options(dead_cards)
    aggressive_options =  \
        range_action.aggressive_range.generate_options(dead_cards)
    terminate = False
    if not can_fold:
        if can_call:
            allowed_options = passive_options + aggressive_options
        else:
            # On the river, heads-up, if we called it would end the hand
            # (like a fold elsewhere)
            allowed_options = aggressive_options
            if not allowed_options:
                # The hand must end. Now.
                # They have no bet/raise range, so they cannot raise.
                # They cannot call, because the cost and benefit of calling is
                # already handled as a partial showdown payment
                # They cannot necessarily fold, because they might not have a
                # fold range.
                # Example: on the river, heads-up, they call their whole range.
                # In fact, that's more than an example, it happens all the time.
                # In this case, we don't have a showdown, or even complete an
                # action for this range_action. In fact, whether we record a
                # call action or not is perhaps irrelevant.
                terminate = True
        # Edge case: It's just possible that there will be no options here. This
        # can happen when the player's current hand is in their fold range, and
        # due to cards dealt to the board and to other players, they can't have
        # any of the hands in their call or raise ranges.
        # Example: The board has AhAd, and an opponent has AsAc, and all hand in
        # the player's passive and aggressive ranges contain an Ace, and the
        # only options that don't contain an Ace are in the fold range.
        # Resolution: In this case, we let them fold. They will find this
        # astonishing, but... I think we have to.
        if allowed_options:
            description = weighted_options_to_description(allowed_options)
            allowed_range = HandRange(description)
            cards_dealt[dealt_key] = allowed_range.generate_hand()
    # Note that we can't use RelativeSizes for this. Because that doesn't
    # account for card removal effects. I.e. for the opponent's range. But this
    # way indirectly does. Yes, sometimes this strangely means that Hero
    # surprisingly folds 100%. Yes, sometimes this strangely means that Hero
    # folds 0%. And that's okay, because those things really do happen some
    # times. (Although neither might player might know Hero is doing it!)
    fol = len(fold_options)
    pas = len(passive_options)
    agg = len(aggressive_options)
    total = fol + pas + agg
    return (terminate,
        float(fol) / total,
        float(pas) / total,
        float(agg) / total)
Example #22
0
def _range_desc_to_size(range_description):
    """
    Given a range description, determine the number of combos it represents.
    """
    return len(HandRange(range_description).generate_options())
Example #23
0
def range_editor_get():
    """
    An HTML range editor!
    """
    embedded = request.args.get('embedded', 'false')
    raised = request.args.get('raised', '')
    can_check = request.args.get('can_check', '')
    can_raise = request.args.get('can_raise', 'true')
    min_raise = request.args.get('min_raise', '0')
    max_raise = request.args.get('max_raise', '200')
    rng_original = safe_hand_range('rng_original', ANYTHING)
    rng_fold = safe_hand_range('rng_fold', NOTHING)
    rng_passive = safe_hand_range('rng_passive', NOTHING)
    rng_aggressive = safe_hand_range('rng_aggressive', NOTHING)
    l_una = request.args.get('l_una', '') == 'checked'
    l_fol = request.args.get('l_fol', 'checked') == 'checked'
    l_pas = request.args.get('l_pas', 'checked') == 'checked'
    l_agg = request.args.get('l_agg', 'checked') == 'checked'
    board_raw = request.args.get('board', '')
    images = card_names(board_raw)
    board = safe_board_form('board')
    opt_ori = rng_original.generate_options_unweighted(board)
    opt_fol = rng_fold.generate_options_unweighted(board)
    opt_pas = rng_passive.generate_options_unweighted(board)
    opt_agg = rng_aggressive.generate_options_unweighted(board)
    opt_una = list(set(opt_ori) - set(opt_fol) - set(opt_pas) - set(opt_agg))
    rng_unassigned = HandRange(unweighted_options_to_description(opt_una))
    color_maker = ColorMaker(opt_ori=opt_ori,
                             opt_una=opt_una,
                             opt_fol=opt_fol,
                             opt_pas=opt_pas,
                             opt_agg=opt_agg)
    if len(opt_ori) != 0:
        pct_unassigned = 100.0 * len(opt_una) / len(opt_ori)
        pct_fold = 100.0 * len(opt_fol) / len(opt_ori)
        pct_passive = 100.0 * len(opt_pas) / len(opt_ori)
        pct_aggressive = 100.0 * len(opt_agg) / len(opt_ori)
    else:
        pct_unassigned = pct_fold = pct_passive = pct_aggressive = 0.0
    rank_table = make_rank_table(color_maker,
                                 board,
                                 can_check=can_check,
                                 is_raised=raised)
    suited_table = make_suited_table()
    pair_table = make_pair_table()
    offsuit_table = make_offsuit_table()
    hidden_fields = [("raised", raised), ("can_check", can_check),
                     ("can_raise", can_raise), ("min_raise", min_raise),
                     ("max_raise", max_raise), ("board", board_raw),
                     ("rng_original", rng_original.description),
                     ("rng_unassigned", rng_unassigned.description),
                     ("rng_fold", rng_fold.description),
                     ("rng_passive", rng_passive.description),
                     ("rng_aggressive", rng_aggressive.description)]
    if embedded == 'true':
        template = 'web/range_viewer.html'
    else:
        template = 'web/range_editor.html'
    return render_template(template,
                           title="Range Editor",
                           next_map=NEXT_MAP,
                           hidden_fields=hidden_fields,
                           rank_table=rank_table,
                           suited_table=suited_table,
                           pair_table=pair_table,
                           offsuit_table=offsuit_table,
                           card_names=images,
                           rng_unassigned=rng_unassigned.description,
                           rng_fold=rng_fold.description,
                           rng_passive=rng_passive.description,
                           rng_aggressive=rng_aggressive.description,
                           l_una=l_una,
                           l_fol=l_fol,
                           l_pas=l_pas,
                           l_agg=l_agg,
                           pct_unassigned=pct_unassigned,
                           pct_fold=pct_fold,
                           pct_passive=pct_passive,
                           pct_aggressive=pct_aggressive,
                           raised=raised,
                           can_check=can_check,
                           can_raise=can_raise,
                           min_raise=min_raise,
                           max_raise=max_raise)
Example #24
0
    def test_range_action_fits(self):
        """
        Test range_action_fits
        """
        # pylint:disable=R0915

        # will test that:
        # - hand in original but not action should fail
        # - hand not in original but in action should fail
        # - hand in two or more ranges should fail
        # - raise size within band should succeed
        # - raise size outside band should fail
        # - should work the same with weights as without
        range_original = HandRange("AA(5),22,72o")
        range_aa = HandRange("AA(5)")
        range_kk = HandRange("KK")
        range_22 = HandRange("22")
        range_72o = HandRange("72o")
        range_22_72o = HandRange("22,72o")
        range_aa_22 = HandRange("AA(5),22")
        range_empty = HandRange("nothing")
        range_22_weighted = HandRange("22(3)")

        #options = [FoldOption(), CheckOption(), RaiseOption(2, 194)]
        options = ActionOptions(0, False, 2, 194)

        # invalid, raise size too small
        range_action = ActionDetails(range_72o, range_22, range_aa, 1)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(rsn, "raise total must be between 2 and 194")

        # valid, minraise
        range_action = ActionDetails(range_72o, range_22, range_aa, 2)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertTrue(val)

        # valid, never folding when we can check
        range_action = ActionDetails(range_empty, range_22_72o, range_aa, 2)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertTrue(val)

        # valid, max raise
        range_action = ActionDetails(range_72o, range_22, range_aa, 194)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertTrue(val)

        # invalid, raise size too big
        range_action = ActionDetails(range_72o, range_22, range_aa, 195)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(rsn, "raise total must be between 2 and 194")

        # invalid, AA in original but not action
        range_action = ActionDetails(range_72o, range_22, range_empty, 2)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(
            rsn, "hand in original range but not in action ranges: AdAc")

        # invalid, KK in action but not original
        range_action = ActionDetails(range_72o, range_aa_22, range_kk, 2)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(
            rsn, "hand in action ranges but not in original range: KdKc")

        # invalid, AA in multiple ranges
        range_action = ActionDetails(range_72o, range_aa_22, range_aa, 2)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(rsn, "hand in multiple ranges: AdAc")

        #options = [FoldOption(), CallOption(10), RaiseOption(20, 194)]
        options = ActionOptions(10, True, 20, 194)

        # invalid, re-weighted
        range_action = ActionDetails(range_72o, range_22_weighted, range_aa,
                                     20)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(rsn, "weight changed from 1 to 3 for hand 2d2c")

        # valid, empty raise range (still has a raise size, which is okay)
        range_action = ActionDetails(range_aa, range_22_72o, range_empty, 20)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertTrue(val)

        # invalid, raise too big
        range_action = ActionDetails(range_72o, range_22, range_aa, 195)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(rsn, "raise total must be between 20 and 194")

        #options = [FoldOption(), CallOption(194)]
        options = ActionOptions(194)

        # valid, 0 raise size is okay if empty raise range
        range_action = ActionDetails(range_22_72o, range_aa, range_empty, 0)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertTrue(val)

        # valid, 200 raise size is okay if empty raise range
        range_action = ActionDetails(range_22_72o, range_aa, range_empty, 200)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertTrue(val)

        # valid, has raise size but raise range is empty
        range_action = ActionDetails(range_original, range_empty, range_empty,
                                     20)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertTrue(val)

        # invalid, has raise range
        range_action = ActionDetails(range_72o, range_22, range_aa, 20)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(
            rsn, "there was a raising range, but raising was not an option")

        range_action = ActionDetails(range_72o, range_22, range_aa, 0)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(
            rsn, "there was a raising range, but raising was not an option")

        # invalid, doesn't equal original
        range_action = ActionDetails(range_empty, range_aa, range_empty, 0)
        val, rsn = range_action_fits(range_action, options, range_original)
        self.assertFalse(val)
        self.assertEqual(
            rsn, "hand in original range but not in action ranges: 2d2c")
Example #25
0
 def get_range(self):
     """
     Get range, as HandRange instance
     """
     return HandRange(self.range_raw)