def __init__(self, opt_ori, opt_una, opt_fol, opt_pas, opt_agg, l_una, l_fol, l_pas, l_agg, options_selected, action): """ opt_* = original, unassigned, fold, passive, aggressive options l_* = locked ranges options_selected = options selected action = reset, fold, passive, aggressive """ opt_ori = set(opt_ori) opt_una = set(opt_una) opt_fol = set(opt_fol) opt_pas = set(opt_pas) opt_agg = set(opt_agg) # hands that are selected, are in original moving = set(options_selected).intersection(opt_ori) # remove locked hands self.did_lock = False if l_una: self.did_lock = remove_moving(moving, opt_una) or self.did_lock if l_fol: self.did_lock = remove_moving(moving, opt_fol) or self.did_lock if l_pas: self.did_lock = remove_moving(moving, opt_pas) or self.did_lock if l_agg: self.did_lock = remove_moving(moving, opt_agg) or self.did_lock # now move moving to target, remove from the others if action == 'reset': target = opt_una elif action == 'fold': target = opt_fol elif action == 'passive': target = opt_pas elif action == 'aggressive': target = opt_agg else: # garbage in, garbage out target = opt_una pre = len(target) target.update(moving) for other in [opt_una, opt_fol, opt_pas, opt_agg]: if other is not target: other.difference_update(moving) self.did_move = len(target) != pre self.did_select = bool(options_selected) self.opt_una = opt_una self.opt_fol = opt_fol self.opt_pas = opt_pas self.opt_agg = opt_agg self.rng_unassigned = unweighted_options_to_description(opt_una) self.rng_fold = unweighted_options_to_description(opt_fol) self.rng_passive = unweighted_options_to_description(opt_pas) self.rng_aggressive = unweighted_options_to_description(opt_agg)
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)]
def _range_action_to_vars(item, index): """ Convert to percentages (relative), and such. Returns (total_range, fold_range, passive_range, aggressive_range, username, fold_pct, passive_pct, aggressive_pct, raise_total) """ fold_options = item.range_action.fold_range \ .generate_options_unweighted() passive_options = item.range_action.passive_range \ .generate_options_unweighted() aggressive_options = item.range_action.aggressive_range \ .generate_options_unweighted() all_options = fold_options + passive_options + aggressive_options combined_range = unweighted_options_to_description(all_options) fold_total = len(fold_options) passive_total = len(passive_options) aggressive_total = len(aggressive_options) total = len(all_options) # NOTE: some of this is necessarily common with ACTION_SUMMARY return {"screenname": item.user.screenname, "fold_pct": 100.0 * fold_total / total, "passive_pct": 100.0 * passive_total / total, "aggressive_pct": 100.0 * aggressive_total / total, "raise_total": item.range_action.raise_total, "is_check": item.is_check, "is_raise": item.is_raise, "original": combined_range, "fold": item.range_action.fold_range.description, "passive": item.range_action.passive_range.description, "aggressive": item.range_action.aggressive_range.description, "index": index}
def _range_action_to_vars(item): """ Convert to percentages (relative), and such. Returns (total_range, fold_range, passive_range, aggressive_range, username, fold_pct, passive_pct, aggressive_pct, raise_total) """ fold_options = item.range_action.fold_range \ .generate_options() passive_options = item.range_action.passive_range \ .generate_options() aggressive_options = item.range_action.aggressive_range \ .generate_options() all_options = fold_options + passive_options + aggressive_options combined_range = unweighted_options_to_description(all_options) fold_total = len(fold_options) passive_total = len(passive_options) aggressive_total = len(aggressive_options) total = len(all_options) # NOTE: some of this is necessarily common with ACTION_SUMMARY return {"screenname": item.user.screenname, "fold_pct": 100.0 * fold_total / total, "passive_pct": 100.0 * passive_total / total, "aggressive_pct": 100.0 * aggressive_total / total, "raise_total": item.range_action.raise_total, "is_check": item.is_check, "is_raise": item.is_raise, "original": combined_range, "fold": item.range_action.fold_range.description, "passive": item.range_action.passive_range.description, "aggressive": item.range_action.aggressive_range.description, "order": item.order}
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) ]
def calculate_combo_ev(self, combo, userid): """ Calculate EV for a combo at this point in the game tree. """ if self.children: # intermediate node, EV is combination of children's # oh, each child needs a weight / probability # oh, it's combo specific... "it depends" ;) # EV of combo is: # weighted sum of EV of children, but only for children where the # combo is present (where combo isn't present, probability is zero) # to assess probability: # - if this node's children are performed by this user: # - EV is the EV of the action that contains this combo # - otherwise: # - remove combo from the children's actor's current range # - consider how many combo's of children's actor's current range # proceed to each child # - voila # This conveniently works even in a multi-way pot. It's a very good # approximation of the true probabilities. And note that truly # calculating the true probabilities is not possible. actor = self.children[0].actor if actor == userid: # EV is the EV of the action that contains this combo for node in self.children: if range_contains_hand(node.ranges_by_userid[userid], combo): return node.combo_ev(combo, userid) raise InvalidComboForTree('Combo not in child ranges for userid' ' %d at betting line %s.' % (userid, line_description(self.betting_line))) else: # probabilistic weighting of child EVs # size of bucket is probability of this child valid_children = [child for child in self.children if range_contains_hand(child.ranges_by_userid[userid], combo)] buckets = {child: child.ranges_by_userid[actor] \ .generate_options(Card.many_from_text(child.board) + list(combo)) for child in valid_children} total = len(concatenate(buckets.values())) if total == 0: raise InvalidComboForTree('Combo not in child ranges for' ' userid %d at betting line %s. ' % (userid, line_description(self.betting_line))) probabilities = {child: 1.0 * len(buckets[child]) / total for child in valid_children} ev = sum(probabilities[child] * child.combo_ev(combo, userid) for child in valid_children) return ev # Invalid combos are ignored / not calculated or aggregated. elif userid not in self.winners: # they folded return 0.0 - self.total_contrib[userid] elif len(self.winners) == 1: # uncontested pot return 0.0 + self.final_pot - self.total_contrib[userid] else: # showdown ranges = {userid: range_ for userid, range_ in self.ranges_by_userid.items()} combos = set([combo]) description = unweighted_options_to_description(combos) ranges[userid] = HandRange(description) equities, _iteration = \ showdown_equity(ranges, Card.many_from_text(self.board), hard_limit=10000) # TODO: 1: this is not good enough equity = equities[userid] return equity * self.final_pot - self.total_contrib[userid]
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)
def set_range(self, range_): """ Set range, from HandRange instance """ self.range_raw = unweighted_options_to_description( range_.generate_options())